Compare commits
	
		
			37 Commits
		
	
	
		
			build-2576
			...
			build-abb2
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| abb22519eb | |||
| 87f77543e2 | |||
| 429f2176f2 | |||
| a56b8ae2b5 | |||
| 4324620932 | |||
| 265e839dc7 | |||
| 2144ca2cca | |||
| bf21f92c6f | |||
| 41e8d2c540 | |||
| 047f51fd96 | |||
| 08da50705c | |||
| 3c216af814 | |||
| 6b5ab5acba | |||
| f723d55d7e | |||
| c0d0b7521e | |||
| 7536c67589 | |||
| 0770772e7d | |||
| c6b1289f5a | |||
| 788fe49aa4 | |||
| 3be0f24eac | |||
| 9fe7c458e9 | |||
| 8430e68167 | |||
| 53a76c7a73 | |||
| 70baa30127 | |||
| 283bc5acb4 | |||
| 26a5d20e26 | |||
| ca1a91e0f0 | |||
| 26fe225577 | |||
| 9a95bddf08 | |||
| c880d8e657 | |||
| ac87a140cc | |||
| 0dbe3a866b | |||
| 7c50c58a90 | |||
| ceff1eb1ef | |||
| 46d6d429bb | |||
| dd9e71c9a2 | |||
| 6d2ffb8a6e | 
							
								
								
									
										17
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -1,17 +0,0 @@ | |||||||
| on: [push] |  | ||||||
|  |  | ||||||
| name: Build |  | ||||||
|  |  | ||||||
| jobs: |  | ||||||
|   build-ubuntu: |  | ||||||
|     name: Commit release |  | ||||||
|     runs-on: ubuntu-latest |  | ||||||
|     steps: |  | ||||||
|       - name: Checkout code |  | ||||||
|         uses: actions/checkout@v2 |  | ||||||
|       - name: Setup JDK |  | ||||||
|         uses: actions/setup-java@v1 |  | ||||||
|         with: |  | ||||||
|           java-version: 11 |  | ||||||
|       - name: Build |  | ||||||
|         run: ./gradlew build packageUberJarForCurrentOS |  | ||||||
							
								
								
									
										10
									
								
								.github/workflows/commit-release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -19,12 +19,12 @@ jobs: | |||||||
|       - name: Set version from gradle.properties |       - name: Set version from gradle.properties | ||||||
|         run: echo "version=` cat gradle.properties | grep ^version= | grep -o [\\.0-9]* `" >> $GITHUB_ENV |         run: echo "version=` cat gradle.properties | grep ^version= | grep -o [\\.0-9]* `" >> $GITHUB_ENV | ||||||
|       - name: Build |       - name: Build | ||||||
|         run: ./gradlew build packageUberJarForCurrentOS |         run: ./gradlew build packageReleaseUberJarForCurrentOS | ||||||
|       - name: Publish Web |       - name: Publish Web | ||||||
|         uses: peaceiris/actions-gh-pages@v3 |         uses: peaceiris/actions-gh-pages@v3 | ||||||
|         with: |         with: | ||||||
|           github_token: ${{ secrets.GITHUB_TOKEN }} |           github_token: ${{ secrets.GITHUB_TOKEN }} | ||||||
|           publish_dir: ./web/build/distributions |           publish_dir: ./core/build/dist/js/productionExecutable | ||||||
|           publish_branch: site |           publish_branch: site | ||||||
|       - name: Create Release |       - name: Create Release | ||||||
|         id: create_release |         id: create_release | ||||||
| @@ -38,12 +38,12 @@ jobs: | |||||||
|           draft: false |           draft: false | ||||||
|           prerelease: true |           prerelease: true | ||||||
|       - name: Upload Ubuntu Release Asset |       - name: Upload Ubuntu Release Asset | ||||||
|         id: upload-ubuntu-release-asset  |         id: upload-ubuntu-release-asset | ||||||
|         uses: actions/upload-release-asset@v1 |         uses: actions/upload-release-asset@v1 | ||||||
|         env: |         env: | ||||||
|           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||||||
|         with: |         with: | ||||||
|           upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps  |           upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps | ||||||
|           asset_path: "./desktop/build/compose/jars/kmppscriptbuilder.desktop-linux-x64-${{ env.version }}${{ env.additional_version }}.jar" |           asset_path: "./core/build/compose/jars/kmppscriptbuilder.core-linux-x64-${{ env.version }}${{ env.additional_version }}.jar" | ||||||
|           asset_name: KotlinPublicationScriptsBuilder-linux-x64.jar |           asset_name: KotlinPublicationScriptsBuilder-linux-x64.jar | ||||||
|           asset_content_type: application/java-archive |           asset_content_type: application/java-archive | ||||||
|   | |||||||
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -10,3 +10,4 @@ build/ | |||||||
| out/ | out/ | ||||||
|  |  | ||||||
| local.properties | local.properties | ||||||
|  | kotlin-js-store/ | ||||||
|   | |||||||
							
								
								
									
										12
									
								
								build.gradle
									
									
									
									
									
								
							
							
						
						| @@ -1,6 +1,5 @@ | |||||||
| buildscript { | buildscript { | ||||||
|     repositories { |     repositories { | ||||||
|         jcenter() |  | ||||||
|         google() |         google() | ||||||
|         mavenCentral() |         mavenCentral() | ||||||
|         mavenLocal() |         mavenLocal() | ||||||
| @@ -8,21 +7,18 @@ buildscript { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     dependencies { |     dependencies { | ||||||
|         classpath 'com.android.tools.build:gradle:4.0.2' |         classpath libs.buildscript.kt.gradle | ||||||
|         classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" |         classpath libs.buildscript.kt.serialization | ||||||
|         classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version" |         classpath libs.buildscript.jb.dokka | ||||||
|         classpath "com.getkeepsafe.dexcount:dexcount-gradle-plugin:$dexcount_version" |         classpath libs.buildscript.gh.release | ||||||
|         classpath "org.jetbrains.dokka:dokka-gradle-plugin:$dokka_version" |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| allprojects { | allprojects { | ||||||
|     repositories { |     repositories { | ||||||
|         mavenLocal() |         mavenLocal() | ||||||
|         jcenter() |  | ||||||
|         mavenCentral() |         mavenCentral() | ||||||
|         google() |         google() | ||||||
|         maven { url "https://kotlin.bintray.com/kotlinx" } |  | ||||||
|         maven { url "https://maven.pkg.jetbrains.space/public/p/compose/dev" } |         maven { url "https://maven.pkg.jetbrains.space/public/p/compose/dev" } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,20 +1,46 @@ | |||||||
| plugins { | plugins { | ||||||
|     id "org.jetbrains.kotlin.multiplatform" |     id "org.jetbrains.kotlin.multiplatform" | ||||||
|     id "org.jetbrains.kotlin.plugin.serialization" |     id "org.jetbrains.kotlin.plugin.serialization" | ||||||
|     id "com.android.library" |     alias(libs.plugins.jb.compose) | ||||||
| } | } | ||||||
|  |  | ||||||
| apply from: "$mppProjectWithSerializationPresetPath" | apply from: "$mppProjectWithSerializationPresetPath" | ||||||
|  |  | ||||||
| kotlin { | kotlin { | ||||||
|  |     js (IR) { | ||||||
|  |         binaries.executable() | ||||||
|  |     } | ||||||
|     sourceSets { |     sourceSets { | ||||||
|         commonMain { |         commonMain { | ||||||
|             dependencies { |             dependencies { | ||||||
|                 api "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version" |                 api libs.kt.coroutines | ||||||
|                 api "dev.inmo:micro_utils.coroutines:$micro_utils_version" |                 api libs.microutils.common | ||||||
|  |                 api libs.microutils.coroutines | ||||||
|                 api "io.ktor:ktor-client-core:$ktor_version" |                 api libs.ktor.client | ||||||
|  |                 api(compose.runtime) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         jsMain { | ||||||
|  |             dependencies { | ||||||
|  |                 implementation(compose.web.core) | ||||||
|  |                 api libs.ktor.client.js | ||||||
|  |                 api libs.jsuikit | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         jvmMain { | ||||||
|  |             dependencies { | ||||||
|  |                 implementation(compose.desktop.currentOs) | ||||||
|  |                 api libs.ktor.client.cio | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | compose { | ||||||
|  |     desktop { | ||||||
|  |         application { | ||||||
|  |             mainClass = "dev.inmo.kmppscriptbuilder.desktop.BuilderKt" | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|   | |||||||
| @@ -0,0 +1,48 @@ | |||||||
|  | package dev.inmo.kmppscriptbuilder.core.export | ||||||
|  |  | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.models.MavenConfig | ||||||
|  |  | ||||||
|  | const val generateCentralSonatypeUploadingPartImports = """import java.nio.charset.StandardCharsets | ||||||
|  | import java.net.http.HttpClient | ||||||
|  | import java.net.http.HttpRequest | ||||||
|  | import java.net.http.HttpResponse""" | ||||||
|  | const val generateCentralSonatypeUploadingPart = """if ((project.hasProperty('SONATYPE_USER') || System.getenv('SONATYPE_USER') != null) && (project.hasProperty('SONATYPE_PASSWORD') || System.getenv('SONATYPE_PASSWORD') != null)) { | ||||||
|  |     def taskName = "uploadSonatypePublication" | ||||||
|  |     if (rootProject.tasks.names.contains(taskName) == false) { | ||||||
|  |         rootProject.tasks.register(taskName) { | ||||||
|  |             doLast { | ||||||
|  |                 def username = project.hasProperty('SONATYPE_USER') ? project.property('SONATYPE_USER') : System.getenv('SONATYPE_USER') | ||||||
|  |                 def password = project.hasProperty('SONATYPE_PASSWORD') ? project.property('SONATYPE_PASSWORD') : System.getenv('SONATYPE_PASSWORD') | ||||||
|  |                 def bearer = Base64.getEncoder().encodeToString("${"$"}username:${"$"}password".getBytes(StandardCharsets.UTF_8)) | ||||||
|  |      | ||||||
|  |                 def client = HttpClient.newHttpClient() | ||||||
|  |                 def request = HttpRequest.newBuilder() | ||||||
|  |                         .uri(URI.create("https://ossrh-staging-api.central.sonatype.com/manual/search/repositories?state=open")) | ||||||
|  |                         .GET() | ||||||
|  |                         .header("Content-Type", "application/json") | ||||||
|  |                         .header("Authorization", "Bearer ${"$"}bearer") | ||||||
|  |                         .build() | ||||||
|  |      | ||||||
|  |                 def response = client.send(request, HttpResponse.BodyHandlers.ofString()) | ||||||
|  |                 def keys = new ArrayList<String>() | ||||||
|  |                 response.body().findAll("\"key\"[\\s]*:[\\s]*\"[^\"]+\"").forEach { | ||||||
|  |                     def key = it.find("[^\"]+\"\$").find("[^\"]+") | ||||||
|  |                     keys.add(key) | ||||||
|  |                 } | ||||||
|  |                 keys.forEach { | ||||||
|  |                     println("Start uploading ${"$"}it") | ||||||
|  |                     def uploadRequest = HttpRequest.newBuilder() | ||||||
|  |                             .uri(URI.create("https://ossrh-staging-api.central.sonatype.com/manual/upload/repository/${"$"}it?publishing_type=user_managed")) | ||||||
|  |                             .POST(HttpRequest.BodyPublishers.ofString("")) | ||||||
|  |                             .header("Content-Type", "application/json") | ||||||
|  |                             .header("Authorization", "Bearer ${"$"}bearer") | ||||||
|  |                             .build() | ||||||
|  |                     def uploadResponse = client.send(uploadRequest, HttpResponse.BodyHandlers.ofString()) | ||||||
|  |                     if (uploadResponse.statusCode() != 200) { | ||||||
|  |                         throw IllegalStateException("Faced error of uploading for repo with key ${"$"}it. Response: ${"$"}uploadResponse") | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | }""" | ||||||
| @@ -0,0 +1,87 @@ | |||||||
|  | package dev.inmo.kmppscriptbuilder.core.export | ||||||
|  |  | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.models.GpgSigning | ||||||
|  |  | ||||||
|  | fun GpgSigning.generateMavenConfig() = when (this) { | ||||||
|  |     GpgSigning.Disabled -> "" | ||||||
|  |     GpgSigning.Optional -> | ||||||
|  | """ | ||||||
|  | if (project.hasProperty("signing.gnupg.keyName")) { | ||||||
|  |     apply plugin: 'signing' | ||||||
|  |  | ||||||
|  |     signing { | ||||||
|  |         useGpgCmd() | ||||||
|  |  | ||||||
|  |         sign publishing.publications | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     task signAll { | ||||||
|  |         tasks.withType(Sign).forEach { | ||||||
|  |             dependsOn(it) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Workaround to make android sign operations depend on signing tasks | ||||||
|  |     project.getTasks().withType(AbstractPublishToMaven.class).configureEach { | ||||||
|  |         def signingTasks = project.getTasks().withType(Sign.class) | ||||||
|  |         mustRunAfter(signingTasks) | ||||||
|  |     } | ||||||
|  |     // Workaround to make test tasks use sign | ||||||
|  |     project.getTasks().withType(Sign.class).configureEach { signTask -> | ||||||
|  |         def withoutSign = (signTask.name.startsWith("sign") ? signTask.name.minus("sign") : signTask.name) | ||||||
|  |         def pubName = withoutSign.endsWith("Publication") ? withoutSign.substring(0, withoutSign.length() - "Publication".length()) : withoutSign | ||||||
|  |         // These tasks only exist for native targets, hence findByName() to avoid trying to find them for other targets | ||||||
|  |  | ||||||
|  |         // Task ':linkDebugTest<platform>' uses this output of task ':sign<platform>Publication' without declaring an explicit or implicit dependency | ||||||
|  |         def debugTestTask = tasks.findByName("linkDebugTest${'$'}pubName") | ||||||
|  |         if (debugTestTask != null) { | ||||||
|  |             signTask.mustRunAfter(debugTestTask) | ||||||
|  |         } | ||||||
|  |         // Task ':compileTestKotlin<platform>' uses this output of task ':sign<platform>Publication' without declaring an explicit or implicit dependency | ||||||
|  |         def testTask = tasks.findByName("compileTestKotlin${'$'}pubName") | ||||||
|  |         if (testTask != null) { | ||||||
|  |             signTask.mustRunAfter(testTask) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | """ | ||||||
|  |     GpgSigning.Enabled -> | ||||||
|  | """ | ||||||
|  | apply plugin: 'signing' | ||||||
|  |  | ||||||
|  | signing { | ||||||
|  |     useGpgCmd() | ||||||
|  |  | ||||||
|  |     sign publishing.publications | ||||||
|  | } | ||||||
|  |  | ||||||
|  | task signAll { | ||||||
|  |     tasks.withType(Sign).forEach { | ||||||
|  |         dependsOn(it) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Workaround to make android sign operations depend on signing tasks | ||||||
|  | project.getTasks().withType(AbstractPublishToMaven.class).configureEach { | ||||||
|  |     def signingTasks = project.getTasks().withType(Sign.class) | ||||||
|  |     mustRunAfter(signingTasks) | ||||||
|  | } | ||||||
|  | // Workaround to make test tasks use sign | ||||||
|  | project.getTasks().withType(Sign.class).configureEach { signTask -> | ||||||
|  |     def withoutSign = (signTask.name.startsWith("sign") ? signTask.name.minus("sign") : signTask.name) | ||||||
|  |     def pubName = withoutSign.endsWith("Publication") ? withoutSign.substring(0, withoutSign.length() - "Publication".length()) : withoutSign | ||||||
|  |     // These tasks only exist for native targets, hence findByName() to avoid trying to find them for other targets | ||||||
|  |  | ||||||
|  |     // Task ':linkDebugTest<platform>' uses this output of task ':sign<platform>Publication' without declaring an explicit or implicit dependency | ||||||
|  |     def debugTestTask = tasks.findByName("linkDebugTest${'$'}pubName") | ||||||
|  |     if (debugTestTask != null) { | ||||||
|  |         signTask.mustRunAfter(debugTestTask) | ||||||
|  |     } | ||||||
|  |     // Task ':compileTestKotlin<platform>' uses this output of task ':sign<platform>Publication' without declaring an explicit or implicit dependency | ||||||
|  |     def testTask = tasks.findByName("compileTestKotlin${'$'}pubName") | ||||||
|  |     if (testTask != null) { | ||||||
|  |         signTask.mustRunAfter(testTask) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | """ | ||||||
|  | } | ||||||
| @@ -0,0 +1,71 @@ | |||||||
|  | package dev.inmo.kmppscriptbuilder.core.export.js_only | ||||||
|  |  | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.export.generateCentralSonatypeUploadingPart | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.export.generateCentralSonatypeUploadingPartImports | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.export.generateMavenConfig | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.models.* | ||||||
|  |  | ||||||
|  | fun MavenConfig.buildJsOnlyMavenConfig(licenses: List<License>): String = """ | ||||||
|  | ${if (includeCentralSonatypeUploadingScript) "$generateCentralSonatypeUploadingPartImports\n" else ""} | ||||||
|  | apply plugin: 'maven-publish' | ||||||
|  | ${if (includeCentralSonatypeUploadingScript) "$generateCentralSonatypeUploadingPart\n" else ""} | ||||||
|  |  | ||||||
|  | task javadocJar(type: Jar) { | ||||||
|  |     archiveClassifier = 'javadoc' | ||||||
|  | } | ||||||
|  | task sourcesJar(type: Jar) { | ||||||
|  |     kotlin.sourceSets.all { | ||||||
|  |         from(kotlin) | ||||||
|  |     } | ||||||
|  |     archiveClassifier = 'sources' | ||||||
|  | } | ||||||
|  |  | ||||||
|  | publishing { | ||||||
|  |     publications { | ||||||
|  |         maven(MavenPublication) { | ||||||
|  |             kotlin.js().components.forEach { | ||||||
|  |                 from(it) | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             artifact javadocJar | ||||||
|  |             artifact sourcesJar | ||||||
|  |  | ||||||
|  |             pom { | ||||||
|  |                 resolveStrategy = Closure.DELEGATE_FIRST | ||||||
|  |  | ||||||
|  |                 description = "$description" | ||||||
|  |                 name = "$name" | ||||||
|  |                 url = "$url" | ||||||
|  |  | ||||||
|  |                 scm { | ||||||
|  |                     developerConnection = "scm:git:[fetch=]${vcsUrl}[push=]${vcsUrl}" | ||||||
|  |                     url = "$vcsUrl" | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 developers { | ||||||
|  |                     ${developers.joinToString("\n") { """ | ||||||
|  |                         developer { | ||||||
|  |                             id = "${it.id}" | ||||||
|  |                             name = "${it.name}" | ||||||
|  |                             email = "${it.eMail}" | ||||||
|  |                         } | ||||||
|  |                     """ }} | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 licenses { | ||||||
|  |                     ${licenses.joinToString("\n") { """ | ||||||
|  |                         license { | ||||||
|  |                             name = "${it.title}" | ||||||
|  |                             url = "${it.url}" | ||||||
|  |                         } | ||||||
|  |                     """ }} | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             repositories { | ||||||
|  |                 ${repositories.joinToString("\n                ") { it.build("                ") }} | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | ${gpgSigning.generateMavenConfig()} | ||||||
|  | """.trimIndent() | ||||||
| @@ -1,69 +1,68 @@ | |||||||
| package dev.inmo.kmppscriptbuilder.core.export.jvm_only | package dev.inmo.kmppscriptbuilder.core.export.jvm_only | ||||||
|  |  | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.export.generateCentralSonatypeUploadingPart | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.export.generateCentralSonatypeUploadingPartImports | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.export.generateMavenConfig | ||||||
| import dev.inmo.kmppscriptbuilder.core.models.* | import dev.inmo.kmppscriptbuilder.core.models.* | ||||||
|  |  | ||||||
| fun MavenConfig.buildJvmOnlyMavenConfig(licenses: List<License>): String = """ | fun MavenConfig.buildJvmOnlyMavenConfig(licenses: List<License>): String = """ | ||||||
|     apply plugin: 'maven-publish' | ${if (includeCentralSonatypeUploadingScript) "$generateCentralSonatypeUploadingPartImports\n" else ""} | ||||||
|     ${if (includeGpgSigning) "apply plugin: 'signing'\n" else ""} | apply plugin: 'maven-publish' | ||||||
|      | ${if (includeCentralSonatypeUploadingScript) "$generateCentralSonatypeUploadingPart\n" else ""} | ||||||
|     task javadocJar(type: Jar) { |  | ||||||
|         from javadoc |  | ||||||
|         classifier = 'javadoc' |  | ||||||
|     } |  | ||||||
|     task sourcesJar(type: Jar) { |  | ||||||
|         from sourceSets.main.allSource |  | ||||||
|         classifier = 'sources' |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     publishing { | task javadocJar(type: Jar) { | ||||||
|         publications { |     from javadoc | ||||||
|             maven(MavenPublication) { |     archiveClassifier = 'javadoc' | ||||||
|                 from components.java | } | ||||||
|      | task sourcesJar(type: Jar) { | ||||||
|                 artifact javadocJar |     from sourceSets.main.allSource | ||||||
|                 artifact sourcesJar |     archiveClassifier = 'sources' | ||||||
|  | } | ||||||
|  |  | ||||||
|                 pom { | publishing { | ||||||
|                     resolveStrategy = Closure.DELEGATE_FIRST |     publications { | ||||||
|  |         maven(MavenPublication) { | ||||||
|  |             from components.java | ||||||
|  |  | ||||||
|                     description = "$description" |             artifact javadocJar | ||||||
|                     name = "$name" |             artifact sourcesJar | ||||||
|                     url = "$url" |  | ||||||
|  |  | ||||||
|                     scm { |             pom { | ||||||
|                         developerConnection = "scm:git:[fetch=]${vcsUrl}[push=]${vcsUrl}" |                 resolveStrategy = Closure.DELEGATE_FIRST | ||||||
|                         url = "$vcsUrl" |  | ||||||
|                     } |  | ||||||
|  |  | ||||||
|                     developers { |                 description = "$description" | ||||||
|                         ${developers.joinToString("\n") { """ |                 name = "$name" | ||||||
|                             developer { |                 url = "$url" | ||||||
|                                 id = "${it.id}" |  | ||||||
|                                 name = "${it.name}" |  | ||||||
|                                 email = "${it.eMail}" |  | ||||||
|                             } |  | ||||||
|                         """ }} |  | ||||||
|                     } |  | ||||||
|  |  | ||||||
|                     licenses { |                 scm { | ||||||
|                         ${licenses.joinToString("\n") { """ |                     developerConnection = "scm:git:[fetch=]${vcsUrl}[push=]${vcsUrl}" | ||||||
|                             license { |                     url = "$vcsUrl" | ||||||
|                                 name = "${it.title}" |  | ||||||
|                                 url = "${it.url}" |  | ||||||
|                             } |  | ||||||
|                         """ }} |  | ||||||
|                     } |  | ||||||
|                 } |                 } | ||||||
|                 repositories { |  | ||||||
|                     ${repositories.joinToString("\n                    ") { it.build("                    ") }} |                 developers { | ||||||
|  |                     ${developers.joinToString("\n") { """ | ||||||
|  |                         developer { | ||||||
|  |                             id = "${it.id}" | ||||||
|  |                             name = "${it.name}" | ||||||
|  |                             email = "${it.eMail}" | ||||||
|  |                         } | ||||||
|  |                     """ }} | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|  |                 licenses { | ||||||
|  |                     ${licenses.joinToString("\n") { """ | ||||||
|  |                         license { | ||||||
|  |                             name = "${it.title}" | ||||||
|  |                             url = "${it.url}" | ||||||
|  |                         } | ||||||
|  |                     """ }} | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             repositories { | ||||||
|  |                 ${repositories.joinToString("\n                ") { it.build("                ") }} | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     ${if (includeGpgSigning) """ | } | ||||||
|     signing { | ${gpgSigning.generateMavenConfig()} | ||||||
|         useGpgCmd() | """.trimIndent() | ||||||
|         sign publishing.publications |  | ||||||
|     } |  | ||||||
|     """ else ""} |  | ||||||
| """.trimIndent() |  | ||||||
|   | |||||||
| @@ -1,56 +1,51 @@ | |||||||
| package dev.inmo.kmppscriptbuilder.core.export.mpp | package dev.inmo.kmppscriptbuilder.core.export.mpp | ||||||
|  |  | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.export.generateCentralSonatypeUploadingPart | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.export.generateCentralSonatypeUploadingPartImports | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.export.generateMavenConfig | ||||||
| import dev.inmo.kmppscriptbuilder.core.models.* | import dev.inmo.kmppscriptbuilder.core.models.* | ||||||
|  |  | ||||||
| fun MavenConfig.buildMultiplatformMavenConfig(licenses: List<License>): String = """ | fun MavenConfig.buildMultiplatformMavenConfig(licenses: List<License>): String = """ | ||||||
|     apply plugin: 'maven-publish' | ${if (includeCentralSonatypeUploadingScript) "$generateCentralSonatypeUploadingPartImports\n" else ""} | ||||||
|     ${if (includeGpgSigning) "apply plugin: 'signing'\n" else ""} | apply plugin: 'maven-publish' | ||||||
|     task javadocsJar(type: Jar) { | ${if (includeCentralSonatypeUploadingScript) "$generateCentralSonatypeUploadingPart\n" else ""} | ||||||
|         classifier = 'javadoc' | task javadocsJar(type: Jar) { | ||||||
|     } |     archiveClassifier = 'javadoc' | ||||||
|  | } | ||||||
|  |  | ||||||
|     publishing { | publishing { | ||||||
|         publications.all { |     publications.all { | ||||||
|             artifact javadocsJar |         artifact javadocsJar | ||||||
|  |  | ||||||
|             pom { |         pom { | ||||||
|                 description = "$description" |             description = "$description" | ||||||
|                 name = "$name" |             name = "$name" | ||||||
|                 url = "$url" |             url = "$url" | ||||||
|  |  | ||||||
|                 scm { |             scm { | ||||||
|                     developerConnection = "scm:git:[fetch=]${vcsUrl}[push=]${vcsUrl}" |                 developerConnection = "scm:git:[fetch=]${vcsUrl}[push=]${vcsUrl}" | ||||||
|                     url = "$vcsUrl" |                 url = "$vcsUrl" | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 developers { |  | ||||||
|                     ${developers.joinToString("\n") { """ |  | ||||||
|                         developer { |  | ||||||
|                             id = "${it.id}" |  | ||||||
|                             name = "${it.name}" |  | ||||||
|                             email = "${it.eMail}" |  | ||||||
|                         } |  | ||||||
|                     """ }} |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 licenses { |  | ||||||
|                     ${licenses.joinToString("\n") { """ |  | ||||||
|                         license { |  | ||||||
|                             name = "${it.title}" |  | ||||||
|                             url = "${it.url}" |  | ||||||
|                         } |  | ||||||
|                     """ }} |  | ||||||
|                 } |  | ||||||
|             } |             } | ||||||
|             repositories { |  | ||||||
|                 ${repositories.joinToString("\n                ") { it.build("                ") }} |             developers {${developers.joinToString("\n") { """ | ||||||
|  |                 developer { | ||||||
|  |                     id = "${it.id}" | ||||||
|  |                     name = "${it.name}" | ||||||
|  |                     email = "${it.eMail}" | ||||||
|  |                 }""" }} | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             licenses {${licenses.joinToString("\n") { """ | ||||||
|  |                 license { | ||||||
|  |                     name = "${it.title}" | ||||||
|  |                     url = "${it.url}" | ||||||
|  |                 }""" }} | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |         repositories { | ||||||
|  |             ${repositories.joinToString("\n            ") { it.build("            ") }} | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|     ${if (includeGpgSigning) """ | } | ||||||
|     signing { |     ${gpgSigning.generateMavenConfig()} | ||||||
|         useGpgCmd() | """.trimIndent() | ||||||
|         sign publishing.publications |  | ||||||
|     } |  | ||||||
|     """ else ""} |  | ||||||
| """.trimIndent() |  | ||||||
|   | |||||||
| @@ -1,5 +1,6 @@ | |||||||
| package dev.inmo.kmppscriptbuilder.core.models | package dev.inmo.kmppscriptbuilder.core.models | ||||||
|  |  | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.export.js_only.buildJsOnlyMavenConfig | ||||||
| import dev.inmo.kmppscriptbuilder.core.export.jvm_only.buildJvmOnlyMavenConfig | import dev.inmo.kmppscriptbuilder.core.export.jvm_only.buildJvmOnlyMavenConfig | ||||||
| import dev.inmo.kmppscriptbuilder.core.export.mpp.buildMultiplatformMavenConfig | import dev.inmo.kmppscriptbuilder.core.export.mpp.buildMultiplatformMavenConfig | ||||||
| import kotlinx.serialization.* | import kotlinx.serialization.* | ||||||
| @@ -32,12 +33,6 @@ object ProjectTypeSerializer : KSerializer<ProjectType> { | |||||||
|  |  | ||||||
| object MultiplatformProjectType : ProjectType() { | object MultiplatformProjectType : ProjectType() { | ||||||
|     override val name: String = "Multiplatform" |     override val name: String = "Multiplatform" | ||||||
| //    override fun buildBintrayGradleConfig( |  | ||||||
| //        bintrayConfig: BintrayConfig, |  | ||||||
| //        licenses: List<License> |  | ||||||
| //    ): String = bintrayConfig.buildMultiplatformGradleConfig( |  | ||||||
| //        licenses |  | ||||||
| //    ) |  | ||||||
|  |  | ||||||
|     override fun buildMavenGradleConfig( |     override fun buildMavenGradleConfig( | ||||||
|         mavenConfig: MavenConfig, |         mavenConfig: MavenConfig, | ||||||
| @@ -49,12 +44,6 @@ object MultiplatformProjectType : ProjectType() { | |||||||
|  |  | ||||||
| object JVMProjectType : ProjectType() { | object JVMProjectType : ProjectType() { | ||||||
|     override val name: String = "JVM" |     override val name: String = "JVM" | ||||||
| //    override fun buildBintrayGradleConfig( |  | ||||||
| //        bintrayConfig: BintrayConfig, |  | ||||||
| //        licenses: List<License> |  | ||||||
| //    ): String = bintrayConfig.buildJvmOnlyGradleConfig( |  | ||||||
| //        licenses |  | ||||||
| //    ) |  | ||||||
|  |  | ||||||
|     override fun buildMavenGradleConfig( |     override fun buildMavenGradleConfig( | ||||||
|         mavenConfig: MavenConfig, |         mavenConfig: MavenConfig, | ||||||
| @@ -64,6 +53,15 @@ object JVMProjectType : ProjectType() { | |||||||
|     ) |     ) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | object JSProjectType : ProjectType() { | ||||||
|  |     override val name: String = "JS" | ||||||
|  |  | ||||||
|  |     override fun buildMavenGradleConfig( | ||||||
|  |         mavenConfig: MavenConfig, | ||||||
|  |         licenses: List<License> | ||||||
|  |     ): String = mavenConfig.buildJsOnlyMavenConfig(licenses) | ||||||
|  | } | ||||||
|  |  | ||||||
| @Serializable | @Serializable | ||||||
| data class Config( | data class Config( | ||||||
|     val licenses: List<License>, |     val licenses: List<License>, | ||||||
|   | |||||||
| @@ -4,6 +4,7 @@ import dev.inmo.kmppscriptbuilder.core.utils.serialFormat | |||||||
| import io.ktor.client.HttpClient | import io.ktor.client.HttpClient | ||||||
| import io.ktor.client.request.get | import io.ktor.client.request.get | ||||||
| import io.ktor.client.request.url | import io.ktor.client.request.url | ||||||
|  | import io.ktor.client.statement.bodyAsText | ||||||
| import kotlinx.serialization.Serializable | import kotlinx.serialization.Serializable | ||||||
| import kotlinx.serialization.builtins.MapSerializer | import kotlinx.serialization.builtins.MapSerializer | ||||||
| import kotlinx.serialization.builtins.serializer | import kotlinx.serialization.builtins.serializer | ||||||
| @@ -20,9 +21,9 @@ private val commonLicensesListDeserializer = MapSerializer(String.serializer(), | |||||||
| private var licenses: Map<String, License>? = null | private var licenses: Map<String, License>? = null | ||||||
|  |  | ||||||
| suspend fun HttpClient.getLicenses(): Map<String, License> { | suspend fun HttpClient.getLicenses(): Map<String, License> { | ||||||
|     val answer = get<String> { |     val answer = get { | ||||||
|         url("https://licenses.opendefinition.org/licenses/groups/all.json") |         url("https://licenses.opendefinition.org/licenses/groups/all.json") | ||||||
|     } |     }.bodyAsText() | ||||||
|     return serialFormat.decodeFromString(commonLicensesListDeserializer, answer).also { gotLicenses -> |     return serialFormat.decodeFromString(commonLicensesListDeserializer, answer).also { gotLicenses -> | ||||||
|         licenses = gotLicenses |         licenses = gotLicenses | ||||||
|     } |     } | ||||||
| @@ -30,19 +31,19 @@ suspend fun HttpClient.getLicenses(): Map<String, License> { | |||||||
|  |  | ||||||
| suspend fun HttpClient.searchLicense(name: String): List<License> { | suspend fun HttpClient.searchLicense(name: String): List<License> { | ||||||
|     val licenses = licenses ?: getLicenses() |     val licenses = licenses ?: getLicenses() | ||||||
|     val lowerCase = name.toLowerCase() |     val lowerCase = name.lowercase() | ||||||
|     val upperCase = name.toUpperCase() |     val upperCase = name.uppercase() | ||||||
|     return licenses.values.filter { |     return licenses.values.filter { | ||||||
|         it.title.toLowerCase().contains(lowerCase) || it.title.toUpperCase().contains(upperCase) || it.title.contains(name) |         it.title.lowercase().contains(lowerCase) || it.title.uppercase().contains(upperCase) || it.title.contains(name) | ||||||
|             || it.id.toLowerCase().contains(lowerCase) || it.id.toUpperCase().contains(upperCase) || it.id.contains(name) |             || it.id.lowercase().contains(lowerCase) || it.id.uppercase().contains(upperCase) || it.id.contains(name) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| fun Map<String, License>.searchLicense(name: String): List<License> { | fun Map<String, License>.searchLicense(name: String): List<License> { | ||||||
|     val lowerCase = name.toLowerCase() |     val lowerCase = name.lowercase() | ||||||
|     val upperCase = name.toUpperCase() |     val upperCase = name.uppercase() | ||||||
|     return values.filter { |     return values.filter { | ||||||
|         it.title.toLowerCase().contains(lowerCase) || it.title.toUpperCase().contains(upperCase) || it.title.contains(name) |         it.title.lowercase().contains(lowerCase) || it.title.uppercase().contains(upperCase) || it.title.contains(name) | ||||||
|             || it.id.toLowerCase().contains(lowerCase) || it.id.toUpperCase().contains(upperCase) || it.id.contains(name) |             || it.id.lowercase().contains(lowerCase) || it.id.uppercase().contains(upperCase) || it.id.contains(name) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -2,40 +2,120 @@ package dev.inmo.kmppscriptbuilder.core.models | |||||||
|  |  | ||||||
| import kotlinx.serialization.Serializable | import kotlinx.serialization.Serializable | ||||||
|  |  | ||||||
|  | const val defaultProjectName = "\${project.name}" | ||||||
|  | const val defaultProjectDescription = "\${project.name}" | ||||||
|  |  | ||||||
|  | @Serializable | ||||||
|  | sealed class GpgSigning(val name: String) { | ||||||
|  |     @Serializable | ||||||
|  |     object Disabled : GpgSigning("Disabled") | ||||||
|  |     @Serializable | ||||||
|  |     object Optional : GpgSigning("Optional") | ||||||
|  |     @Serializable | ||||||
|  |     object Enabled : GpgSigning("Enabled") | ||||||
|  | } | ||||||
|  |  | ||||||
| @Serializable | @Serializable | ||||||
| data class MavenConfig( | data class MavenConfig( | ||||||
|     val name: String, |     val name: String, | ||||||
|     val description: String, |     val description: String, | ||||||
|     val url: String, |     val url: String, | ||||||
|     val vcsUrl: String, |     val vcsUrl: String, | ||||||
|     val includeGpgSigning: Boolean = false, |  | ||||||
|     val developers: List<Developer>, |     val developers: List<Developer>, | ||||||
|     val repositories: List<MavenPublishingRepository> = emptyList() |     val repositories: List<MavenPublishingRepository> = emptyList(), | ||||||
|  |     val gpgSigning: GpgSigning = GpgSigning.Disabled, | ||||||
|  |     @Deprecated("Replaced with gpgSigning") | ||||||
|  |     val includeGpgSigning: Boolean = false, | ||||||
|  |     val includeCentralSonatypeUploadingScript: Boolean = false, | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @Serializable | @Serializable | ||||||
| data class MavenPublishingRepository( | data class MavenPublishingRepository( | ||||||
|     val name: String, |     val name: String, | ||||||
|     val url: String |     val url: String, | ||||||
|  |     val credsType: CredentialsType = CredentialsType.UsernameAndPassword( | ||||||
|  |         CredentialsType.UsernameAndPassword.defaultUsernameProperty(name), | ||||||
|  |         CredentialsType.UsernameAndPassword.defaultPasswordProperty(name), | ||||||
|  |     ) | ||||||
| ) { | ) { | ||||||
|     private val nameCapitalized by lazy { |  | ||||||
|         name.toUpperCase() |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     fun build(indent: String): String { |     @Serializable | ||||||
|         val usernameProperty = "${nameCapitalized}_USER" |     sealed interface CredentialsType { | ||||||
|         val passwordProperty = "${nameCapitalized}_PASSWORD" |         @Serializable | ||||||
|         return """if ((project.hasProperty('${usernameProperty}') || System.getenv('${usernameProperty}') != null) && (project.hasProperty('${passwordProperty}') || System.getenv('${passwordProperty}') != null)) { |         object Nothing: CredentialsType { | ||||||
|     maven { |             override fun buildCheckPart(): String = "true" | ||||||
|         name = "$name" |             override fun buildCredsPart(): String = "" | ||||||
|         url = uri("$url") |         } | ||||||
|  |         @Serializable | ||||||
|  |         data class UsernameAndPassword( | ||||||
|  |             val usernameProperty: String, | ||||||
|  |             val passwordProperty: String | ||||||
|  |         ): CredentialsType { | ||||||
|  |             constructor(baseParameter: String) : this( | ||||||
|  |                 defaultUsernameProperty(baseParameter), | ||||||
|  |                 defaultPasswordProperty(baseParameter) | ||||||
|  |             ) | ||||||
|  |  | ||||||
|  |             override fun buildCheckPart(): String = "(project.hasProperty('${usernameProperty}') || System.getenv('${usernameProperty}') != null) && (project.hasProperty('${passwordProperty}') || System.getenv('${passwordProperty}') != null)" | ||||||
|  |             override fun buildCredsPart(): String { | ||||||
|  | return """ | ||||||
|         credentials { |         credentials { | ||||||
|             username = project.hasProperty('${usernameProperty}') ? project.property('${usernameProperty}') : System.getenv('${usernameProperty}') |             username = project.hasProperty('${usernameProperty}') ? project.property('${usernameProperty}') : System.getenv('${usernameProperty}') | ||||||
|             password = project.hasProperty('${passwordProperty}') ? project.property('${passwordProperty}') : System.getenv('${passwordProperty}') |             password = project.hasProperty('${passwordProperty}') ? project.property('${passwordProperty}') : System.getenv('${passwordProperty}') | ||||||
|  |         }""" | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             companion object { | ||||||
|  |                 fun defaultUsernameProperty(name: String): String { | ||||||
|  |                     return "${name.uppercase()}_USER" | ||||||
|  |                 } | ||||||
|  |                 fun defaultPasswordProperty(name: String): String { | ||||||
|  |                     return "${name.uppercase()}_PASSWORD" | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|  |         @Serializable | ||||||
|  |         data class HttpHeaderCredentials( | ||||||
|  |             val headerName: String, | ||||||
|  |             val headerValueProperty: String | ||||||
|  |         ): CredentialsType { | ||||||
|  |             override fun buildCheckPart(): String = "project.hasProperty('${headerValueProperty}') || System.getenv('${headerValueProperty}') != null" | ||||||
|  |             override fun buildCredsPart(): String { | ||||||
|  | return """ | ||||||
|  |         credentials(HttpHeaderCredentials) { | ||||||
|  |             name = "$headerName" | ||||||
|  |             value = project.hasProperty('${headerValueProperty}') ? project.property('${headerValueProperty}') : System.getenv('${headerValueProperty}') | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         authentication { | ||||||
|  |             header(HttpHeaderAuthentication) | ||||||
|  |         }""" | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             companion object { | ||||||
|  |                 fun defaultValueProperty(name: String): String { | ||||||
|  |                     return "${name.uppercase()}_TOKEN" | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         fun buildCheckPart(): String | ||||||
|  |         fun buildCredsPart(): String | ||||||
|  |     } | ||||||
|  |     private val nameCapitalized by lazy { | ||||||
|  |         name.uppercase() | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fun build(indent: String): String { | ||||||
|  |         return """if (${credsType.buildCheckPart()}) { | ||||||
|  |     maven { | ||||||
|  |         name = "$name" | ||||||
|  |         url = uri("$url") | ||||||
|  | ${credsType.buildCredsPart()} | ||||||
|     } |     } | ||||||
| }""".replace("\n", "\n$indent") | }""".replace("\n", "\n$indent") | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| val SonatypeRepository = MavenPublishingRepository("sonatype", "https://oss.sonatype.org/service/local/staging/deploy/maven2/") | val SonatypeRepository = MavenPublishingRepository("sonatype", "https://oss.sonatype.org/service/local/staging/deploy/maven2/") | ||||||
|  | val CentralSonatypeRepository = MavenPublishingRepository("sonatype", "https://ossrh-staging-api.central.sonatype.com/service/local/staging/deploy/maven2/") | ||||||
|   | |||||||
| @@ -0,0 +1,56 @@ | |||||||
|  | package dev.inmo.kmppscriptbuilder.core.ui | ||||||
|  |  | ||||||
|  | import androidx.compose.runtime.Composable | ||||||
|  | import androidx.compose.runtime.getValue | ||||||
|  | import androidx.compose.runtime.mutableStateOf | ||||||
|  | import androidx.compose.runtime.setValue | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.models.Config | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.DefaultContentColumn | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.DefaultDivider | ||||||
|  |  | ||||||
|  | @Composable | ||||||
|  | expect fun TopAppBar( | ||||||
|  |     config: Config, | ||||||
|  |     saveAvailable: Boolean, | ||||||
|  |     onSaveAvailable: (Boolean) -> Unit, | ||||||
|  |     onNewConfig: (Config) -> Unit | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | class BuilderView : View() { | ||||||
|  |     internal val projectTypeView by mutableStateOf(ProjectTypeView()) | ||||||
|  |     internal val mavenInfoView by mutableStateOf(MavenInfoView()) | ||||||
|  |     internal val licensesView by mutableStateOf(LicensesView()) | ||||||
|  |  | ||||||
|  |     internal var saveAvailableState by mutableStateOf(false) | ||||||
|  |     var config: Config | ||||||
|  |         get() { | ||||||
|  |             return Config(licensesView.licenses, mavenInfoView.mavenConfig, projectTypeView.projectType) | ||||||
|  |         } | ||||||
|  |         set(value) { | ||||||
|  |             licensesView.licenses = value.licenses | ||||||
|  |             mavenInfoView.mavenConfig = value.mavenConfig | ||||||
|  |             projectTypeView.projectType = value.type | ||||||
|  |             saveAvailableState = true | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     @Composable | ||||||
|  |     override fun build() { | ||||||
|  |         TopAppBar( | ||||||
|  |             config, | ||||||
|  |             saveAvailableState, | ||||||
|  |             { | ||||||
|  |                 saveAvailableState = it | ||||||
|  |             } | ||||||
|  |         ) { | ||||||
|  |             config = it | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         DefaultContentColumn { | ||||||
|  |             projectTypeView.build() | ||||||
|  |             DefaultDivider() | ||||||
|  |             licensesView.build() | ||||||
|  |             DefaultDivider() | ||||||
|  |             mavenInfoView.build() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -1,8 +1,13 @@ | |||||||
| package dev.inmo.kmppscriptbuilder.desktop.views | package dev.inmo.kmppscriptbuilder.core.ui | ||||||
| 
 | 
 | ||||||
| import androidx.compose.runtime.* | import androidx.compose.runtime.Composable | ||||||
|  | import androidx.compose.runtime.getValue | ||||||
|  | import androidx.compose.runtime.mutableStateOf | ||||||
|  | import androidx.compose.runtime.setValue | ||||||
| import dev.inmo.kmppscriptbuilder.core.models.Developer | import dev.inmo.kmppscriptbuilder.core.models.Developer | ||||||
| import dev.inmo.kmppscriptbuilder.desktop.utils.* | import dev.inmo.kmppscriptbuilder.core.ui.utils.CommonText | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.CommonTextField | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.DefaultSmallVerticalMargin | ||||||
| 
 | 
 | ||||||
| class DeveloperState( | class DeveloperState( | ||||||
|     id: String = "", |     id: String = "", | ||||||
| @@ -22,10 +27,10 @@ class DevelopersView : ListView<DeveloperState>("Developers info") { | |||||||
|     var developers: List<Developer> |     var developers: List<Developer> | ||||||
|         get() = itemsList.map { it.toDeveloper() } |         get() = itemsList.map { it.toDeveloper() } | ||||||
|         set(value) { |         set(value) { | ||||||
|             itemsList.clear() |             itemsList.apply { | ||||||
|             itemsList.addAll( |                 clear() | ||||||
|                 value.map { it.toDeveloperState() } |                 addAll(value.map { it.toDeveloperState() }) | ||||||
|             ) |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|     override val addItemText: String = "Add developer" |     override val addItemText: String = "Add developer" | ||||||
| @@ -34,18 +39,19 @@ class DevelopersView : ListView<DeveloperState>("Developers info") { | |||||||
|     override fun createItem(): DeveloperState = DeveloperState() |     override fun createItem(): DeveloperState = DeveloperState() | ||||||
|     @Composable |     @Composable | ||||||
|     override fun buildView(item: DeveloperState) { |     override fun buildView(item: DeveloperState) { | ||||||
|  |         CommonText("Developer username") | ||||||
|         CommonTextField( |         CommonTextField( | ||||||
|             item.id, |             item.id, | ||||||
|             "Developer username" |  | ||||||
|         ) { item.id = it } |         ) { item.id = it } | ||||||
|  |         DefaultSmallVerticalMargin() | ||||||
|  |         CommonText("Developer name") | ||||||
|         CommonTextField( |         CommonTextField( | ||||||
|             item.name, |             item.name, | ||||||
|             "Developer name" |  | ||||||
|         ) { item.name = it } |         ) { item.name = it } | ||||||
|  |         DefaultSmallVerticalMargin() | ||||||
|  |         CommonText("Developer E-Mail") | ||||||
|         CommonTextField( |         CommonTextField( | ||||||
|             item.eMail, |             item.eMail, | ||||||
|             "Developer E-Mail" |  | ||||||
|         ) { item.eMail = it } |         ) { item.eMail = it } | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
| } | } | ||||||
| @@ -0,0 +1,103 @@ | |||||||
|  | package dev.inmo.kmppscriptbuilder.core.ui | ||||||
|  |  | ||||||
|  | import androidx.compose.runtime.Composable | ||||||
|  | import androidx.compose.runtime.derivedStateOf | ||||||
|  | import androidx.compose.runtime.getValue | ||||||
|  | import androidx.compose.runtime.mutableStateListOf | ||||||
|  | import androidx.compose.runtime.mutableStateOf | ||||||
|  | import androidx.compose.runtime.setValue | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.models.License | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.models.getLicenses | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.CommonText | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.CommonTextField | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.DefaultSmallVerticalMargin | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.Drawer | ||||||
|  | import io.ktor.client.HttpClient | ||||||
|  | import kotlinx.coroutines.CoroutineScope | ||||||
|  | import kotlinx.coroutines.Dispatchers | ||||||
|  | import kotlinx.coroutines.launch | ||||||
|  |  | ||||||
|  | class LicenseState( | ||||||
|  |     id: String = "", | ||||||
|  |     title: String = "", | ||||||
|  |     url: String? = null | ||||||
|  | ) { | ||||||
|  |     var id: String by mutableStateOf(id) | ||||||
|  |     var title: String by mutableStateOf(title) | ||||||
|  |     var url: String? by mutableStateOf(url) | ||||||
|  |  | ||||||
|  |     fun toLicense() = License(id, title, url) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | internal fun License.toLicenseState() = LicenseState(id, title, url) | ||||||
|  |  | ||||||
|  | expect object LicensesDrawer : Drawer<LicensesView> | ||||||
|  |  | ||||||
|  | class LicensesView : ListView<LicenseState>("Licenses") { | ||||||
|  |     var licenses: List<License> | ||||||
|  |         get() = itemsList.map { it.toLicense() } | ||||||
|  |         set(value) { | ||||||
|  |             itemsList.clear() | ||||||
|  |             itemsList.addAll(value.map { it.toLicenseState() }) | ||||||
|  |         } | ||||||
|  |     internal val availableLicensesState = mutableStateListOf<License>() | ||||||
|  |     internal var licenseSearchFilter by mutableStateOf("") | ||||||
|  |     internal val searchFieldFocused = mutableStateOf(false) | ||||||
|  |     internal val licensesOffersToShow = derivedStateOf { | ||||||
|  |         val query = licenseSearchFilter.lowercase() | ||||||
|  |         availableLicensesState.filter { | ||||||
|  |             it.title.lowercase().contains(query) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     override val addItemText: String | ||||||
|  |         get() = "Add empty license" | ||||||
|  |  | ||||||
|  |     init { | ||||||
|  |         CoroutineScope(Dispatchers.Default).launch { | ||||||
|  |             val client = HttpClient() | ||||||
|  |             availableLicensesState.addAll(client.getLicenses().values) | ||||||
|  |             client.close() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     override fun createItem(): LicenseState = LicenseState() | ||||||
|  |  | ||||||
|  |     @Composable | ||||||
|  |     override fun buildView(item: LicenseState) { | ||||||
|  |         CommonText("License ID") | ||||||
|  |         CommonTextField( | ||||||
|  |             item.id, | ||||||
|  |             "Short name like \"Apache-2.0\"", | ||||||
|  |         ) { item.id = it } | ||||||
|  |         CommonText("License title") | ||||||
|  |         CommonTextField( | ||||||
|  |             item.title, | ||||||
|  |             "Official title of license (like \"Apache Software License 2.0\")", | ||||||
|  |         ) { item.title = it } | ||||||
|  |         CommonText("License URL") | ||||||
|  |         CommonTextField( | ||||||
|  |             item.url ?: "", | ||||||
|  |             "Link to your LICENSE file OR official license file (like \"https://opensource.org/licenses/Apache-2.0\")", | ||||||
|  |         ) { item.url = it } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     override val content: @Composable () -> Unit = { | ||||||
|  |         CommonTextField( | ||||||
|  |             licenseSearchFilter, | ||||||
|  |             "Search filter", | ||||||
|  |             onFocusChanged = { | ||||||
|  |                 searchFieldFocused.value = it | ||||||
|  |             } | ||||||
|  |         ) { filterText -> | ||||||
|  |             licenseSearchFilter = filterText | ||||||
|  |         } | ||||||
|  |         DefaultSmallVerticalMargin() | ||||||
|  |  | ||||||
|  |         with(LicensesDrawer) { draw() } | ||||||
|  |  | ||||||
|  |         DefaultSmallVerticalMargin() | ||||||
|  |  | ||||||
|  |         super.content() | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,26 @@ | |||||||
|  | package dev.inmo.kmppscriptbuilder.core.ui | ||||||
|  |  | ||||||
|  | import androidx.compose.runtime.Composable | ||||||
|  | import androidx.compose.runtime.mutableStateListOf | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.Drawer | ||||||
|  |  | ||||||
|  | expect class ListViewDrawer<T>() : Drawer<ListView<T>> | ||||||
|  |  | ||||||
|  | abstract class ListView<T>(title: String) : VerticalView(title) { | ||||||
|  |     internal val itemsList = mutableStateListOf<T>() | ||||||
|  |  | ||||||
|  |     internal open val addItemText: String = "Add" | ||||||
|  |     internal open val removeItemText: String = "Remove" | ||||||
|  |  | ||||||
|  |     internal abstract fun createItem(): T | ||||||
|  |     @Composable | ||||||
|  |     internal abstract fun buildView(item: T) | ||||||
|  |  | ||||||
|  |     protected val drawer = ListViewDrawer<T>() | ||||||
|  |  | ||||||
|  |     override val content: @Composable () -> Unit = { | ||||||
|  |         with(drawer) { | ||||||
|  |             draw() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,132 @@ | |||||||
|  | package dev.inmo.kmppscriptbuilder.core.ui | ||||||
|  |  | ||||||
|  | import androidx.compose.runtime.* | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.models.CentralSonatypeRepository | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.models.GpgSigning | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.models.MavenConfig | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.models.SonatypeRepository | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.models.defaultProjectDescription | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.models.defaultProjectName | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.ButtonsPanel | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.CommonText | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.CommonTextField | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.DefaultSmallVerticalMargin | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.Drawer | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.SwitchWithLabel | ||||||
|  |  | ||||||
|  | expect class GpgSigningOptionDrawer : Drawer<GpgSigning> | ||||||
|  | expect fun GpgSigningOptionDrawerWithView(view: MavenInfoView): GpgSigningOptionDrawer | ||||||
|  |  | ||||||
|  | class MavenInfoView : VerticalView("Project information") { | ||||||
|  |     internal var projectNameProperty by mutableStateOf("") | ||||||
|  |     internal var projectDescriptionProperty by mutableStateOf("") | ||||||
|  |     internal var projectUrlProperty by mutableStateOf("") | ||||||
|  |     internal var projectVcsUrlProperty by mutableStateOf("") | ||||||
|  |     internal var gpgSignProperty by mutableStateOf<GpgSigning>(GpgSigning.Disabled) | ||||||
|  |     internal var publishToMavenCentralProperty by mutableStateOf(false) | ||||||
|  |     internal var publishToCentralSonatypeProperty by mutableStateOf(false) | ||||||
|  |     internal var includeCentralSonatypeUploadingScriptProperty by mutableStateOf(false) | ||||||
|  |     internal val developersView = DevelopersView() | ||||||
|  |     internal val repositoriesView = RepositoriesView() | ||||||
|  |  | ||||||
|  |     var mavenConfig: MavenConfig | ||||||
|  |         get() = MavenConfig( | ||||||
|  |             name = projectNameProperty.ifBlank { defaultProjectName }, | ||||||
|  |             description = projectDescriptionProperty.ifBlank { defaultProjectDescription }, | ||||||
|  |             url = projectUrlProperty, | ||||||
|  |             vcsUrl = projectVcsUrlProperty, | ||||||
|  |             developers = developersView.developers, | ||||||
|  |             repositories = repositoriesView.repositories + if (publishToMavenCentralProperty) { | ||||||
|  |                 listOf( | ||||||
|  |                     if (publishToCentralSonatypeProperty) { | ||||||
|  |                         CentralSonatypeRepository | ||||||
|  |                     } else { | ||||||
|  |                         SonatypeRepository | ||||||
|  |                     } | ||||||
|  |                 ) | ||||||
|  |             } else { | ||||||
|  |                 emptyList() | ||||||
|  |             }, | ||||||
|  |             gpgSigning = gpgSignProperty, | ||||||
|  |             includeCentralSonatypeUploadingScript = includeCentralSonatypeUploadingScriptProperty | ||||||
|  |         ) | ||||||
|  |         set(value) { | ||||||
|  |             projectNameProperty = value.name | ||||||
|  |             projectDescriptionProperty = value.description | ||||||
|  |             projectUrlProperty = value.url | ||||||
|  |             projectVcsUrlProperty = value.vcsUrl | ||||||
|  |             gpgSignProperty = if (value.includeGpgSigning) { | ||||||
|  |                 GpgSigning.Enabled | ||||||
|  |             } else { | ||||||
|  |                 value.gpgSigning | ||||||
|  |             } | ||||||
|  |             publishToMavenCentralProperty = value.repositories.any { it == SonatypeRepository || it == CentralSonatypeRepository } | ||||||
|  |             developersView.developers = value.developers | ||||||
|  |             repositoriesView.repositories = value.repositories.filter { it != SonatypeRepository && it != CentralSonatypeRepository } | ||||||
|  |             publishToCentralSonatypeProperty = value.repositories.any { it == CentralSonatypeRepository } | ||||||
|  |             includeCentralSonatypeUploadingScriptProperty = value.includeCentralSonatypeUploadingScript | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     private val gpgSigningDrawer = GpgSigningOptionDrawerWithView(this) | ||||||
|  |  | ||||||
|  |     override val content: @Composable () -> Unit = { | ||||||
|  |         CommonText("Public project name") | ||||||
|  |         CommonTextField( | ||||||
|  |             projectNameProperty, | ||||||
|  |             "\${project.name}", | ||||||
|  |         ) { projectNameProperty = it } | ||||||
|  |         DefaultSmallVerticalMargin() | ||||||
|  |         CommonText("Public project description") | ||||||
|  |         CommonTextField( | ||||||
|  |             projectDescriptionProperty, | ||||||
|  |             "\${project.name}", | ||||||
|  |         ) { projectDescriptionProperty = it } | ||||||
|  |         DefaultSmallVerticalMargin() | ||||||
|  |         CommonText("Public project URL") | ||||||
|  |         CommonTextField( | ||||||
|  |             projectUrlProperty, | ||||||
|  |             "Type url to github or other source with readme", | ||||||
|  |         ) { projectUrlProperty = it } | ||||||
|  |         DefaultSmallVerticalMargin() | ||||||
|  |         CommonText("Public project VCS URL (with .git)") | ||||||
|  |         CommonTextField( | ||||||
|  |             projectVcsUrlProperty, | ||||||
|  |             "Type url to github .git file" | ||||||
|  |         ) { projectVcsUrlProperty = it } | ||||||
|  |  | ||||||
|  |         ButtonsPanel( | ||||||
|  |             "Gpg signing", | ||||||
|  |             GpgSigning.Disabled, | ||||||
|  |             GpgSigning.Optional, | ||||||
|  |             GpgSigning.Enabled | ||||||
|  |         ) { | ||||||
|  |             with(gpgSigningDrawer) { | ||||||
|  |                 with (it) { | ||||||
|  |                     draw() | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         SwitchWithLabel( | ||||||
|  |             "Include publication to MavenCentral", | ||||||
|  |             publishToMavenCentralProperty, | ||||||
|  |             placeSwitchAtTheStart = true | ||||||
|  |         ) { publishToMavenCentralProperty = it } | ||||||
|  |         if (publishToMavenCentralProperty) { | ||||||
|  |             SwitchWithLabel( | ||||||
|  |                 "Use Central Sonatype instead of OSSRH (OSSRH has been deprecated)", | ||||||
|  |                 publishToCentralSonatypeProperty, | ||||||
|  |                 placeSwitchAtTheStart = true | ||||||
|  |             ) { publishToCentralSonatypeProperty = it } | ||||||
|  |             if (publishToCentralSonatypeProperty) { | ||||||
|  |                 SwitchWithLabel( | ||||||
|  |                     "Add 'uploadSonatypePublication' root project task (required for Central Sonatype publishing)", | ||||||
|  |                     includeCentralSonatypeUploadingScriptProperty, | ||||||
|  |                     placeSwitchAtTheStart = true | ||||||
|  |                 ) { includeCentralSonatypeUploadingScriptProperty = it } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         developersView.build() | ||||||
|  |         repositoriesView.build() | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,36 @@ | |||||||
|  | package dev.inmo.kmppscriptbuilder.core.ui | ||||||
|  |  | ||||||
|  | import androidx.compose.runtime.Composable | ||||||
|  | import androidx.compose.runtime.getValue | ||||||
|  | import androidx.compose.runtime.mutableStateOf | ||||||
|  | import androidx.compose.runtime.setValue | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.models.JSProjectType | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.models.JVMProjectType | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.models.MultiplatformProjectType | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.models.ProjectType | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.ButtonsPanel | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.DefaultSmallVerticalMargin | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.Drawer | ||||||
|  |  | ||||||
|  | expect class ProjectTypeDrawer : Drawer<ProjectType> | ||||||
|  | expect fun ProjectTypeDrawerWithView(view: ProjectTypeView): ProjectTypeDrawer | ||||||
|  |  | ||||||
|  | class ProjectTypeView : VerticalView("Project type") { | ||||||
|  |     var projectType by mutableStateOf<ProjectType>(MultiplatformProjectType) | ||||||
|  |     private val typeDrawer = ProjectTypeDrawerWithView(this) | ||||||
|  |  | ||||||
|  |     override val content: @Composable () -> Unit = { | ||||||
|  |         ButtonsPanel( | ||||||
|  |             "Project type", | ||||||
|  |             MultiplatformProjectType, | ||||||
|  |             JVMProjectType, | ||||||
|  |             JSProjectType | ||||||
|  |         ) { | ||||||
|  |             with(typeDrawer) { | ||||||
|  |                 with (it) { | ||||||
|  |                     draw() | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,142 @@ | |||||||
|  | package dev.inmo.kmppscriptbuilder.core.ui | ||||||
|  |  | ||||||
|  | import androidx.compose.runtime.Composable | ||||||
|  | import androidx.compose.runtime.getValue | ||||||
|  | import androidx.compose.runtime.mutableStateOf | ||||||
|  | import androidx.compose.runtime.remember | ||||||
|  | import androidx.compose.runtime.setValue | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.models.MavenPublishingRepository | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.ButtonsPanel | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.CommonText | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.CommonTextField | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.DefaultContentColumn | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.DefaultSmallVerticalMargin | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.Drawer | ||||||
|  |  | ||||||
|  | class RepositoryState( | ||||||
|  |     name: String = "", | ||||||
|  |     url: String = "", | ||||||
|  |     credsType: MavenPublishingRepository.CredentialsType = MavenPublishingRepository.CredentialsType.UsernameAndPassword(name) | ||||||
|  | ) { | ||||||
|  |     var name: String by mutableStateOf(name) | ||||||
|  |     var url: String by mutableStateOf(url) | ||||||
|  |     var credsType by mutableStateOf(credsType) | ||||||
|  |  | ||||||
|  |     fun toRepository() = MavenPublishingRepository(name, url, credsType) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | private fun MavenPublishingRepository.toRepositoryState() = RepositoryState(name, url, credsType) | ||||||
|  |  | ||||||
|  | expect class RepositoryCredentialTypeDrawer : Drawer<MavenPublishingRepository.CredentialsType> | ||||||
|  | expect fun RepositoryCredentialTypeDrawerWithState(repositoryState: RepositoryState): RepositoryCredentialTypeDrawer | ||||||
|  |  | ||||||
|  | class RepositoriesView : ListView<RepositoryState>("Repositories info") { | ||||||
|  |     var repositories: List<MavenPublishingRepository> | ||||||
|  |         get() = itemsList.map { it.toRepository() } | ||||||
|  |         set(value) { | ||||||
|  |             itemsList.clear() | ||||||
|  |             itemsList.addAll( | ||||||
|  |                 value.map { it.toRepositoryState() } | ||||||
|  |             ) | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     override val addItemText: String = "Add repository" | ||||||
|  |     override val removeItemText: String = "Remove repository" | ||||||
|  |  | ||||||
|  |     override fun createItem(): RepositoryState = RepositoryState() | ||||||
|  |  | ||||||
|  |     @Composable | ||||||
|  |     override fun buildView(item: RepositoryState) { | ||||||
|  |         val credsTypesDrawer = remember { | ||||||
|  |             RepositoryCredentialTypeDrawerWithState(item) | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         CommonText("Repository name") | ||||||
|  |         CommonTextField( | ||||||
|  |             item.name, | ||||||
|  |             "This name will be used to identify repository in gradle" | ||||||
|  |         ) { | ||||||
|  |             val previous = item.name | ||||||
|  |             item.name = it | ||||||
|  |             when (val currentCredsType = item.credsType) { | ||||||
|  |                 is MavenPublishingRepository.CredentialsType.HttpHeaderCredentials -> { | ||||||
|  |                     if (MavenPublishingRepository.CredentialsType.HttpHeaderCredentials.defaultValueProperty(previous) == currentCredsType.headerValueProperty) { | ||||||
|  |                         item.credsType = currentCredsType.copy( | ||||||
|  |                             headerValueProperty = MavenPublishingRepository.CredentialsType.HttpHeaderCredentials.defaultValueProperty(it) | ||||||
|  |                         ) | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 MavenPublishingRepository.CredentialsType.Nothing -> {} | ||||||
|  |                 is MavenPublishingRepository.CredentialsType.UsernameAndPassword -> { | ||||||
|  |                     var current: MavenPublishingRepository.CredentialsType.UsernameAndPassword = currentCredsType | ||||||
|  |                     if (MavenPublishingRepository.CredentialsType.UsernameAndPassword.defaultUsernameProperty(previous) == currentCredsType.usernameProperty) { | ||||||
|  |                         current = current.copy( | ||||||
|  |                             usernameProperty = MavenPublishingRepository.CredentialsType.UsernameAndPassword.defaultUsernameProperty(it) | ||||||
|  |                         ) | ||||||
|  |                     } | ||||||
|  |                     if (MavenPublishingRepository.CredentialsType.UsernameAndPassword.defaultPasswordProperty(previous) == currentCredsType.passwordProperty) { | ||||||
|  |                         current = current.copy( | ||||||
|  |                             passwordProperty = MavenPublishingRepository.CredentialsType.UsernameAndPassword.defaultPasswordProperty(it) | ||||||
|  |                         ) | ||||||
|  |                     } | ||||||
|  |                     item.credsType = current | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         DefaultSmallVerticalMargin() | ||||||
|  |         CommonText("Repository url") | ||||||
|  |         CommonTextField( | ||||||
|  |             item.url, | ||||||
|  |             "For example: https://repo.maven.apache.org/maven2/" | ||||||
|  |         ) { item.url = it } | ||||||
|  |  | ||||||
|  |         ButtonsPanel( | ||||||
|  |             "Credentials type", | ||||||
|  |             MavenPublishingRepository.CredentialsType.Nothing.takeIf { item.credsType != it } ?: item.credsType, | ||||||
|  |             MavenPublishingRepository.CredentialsType.UsernameAndPassword(item.name).takeIf { item.credsType !is MavenPublishingRepository.CredentialsType.UsernameAndPassword } ?: item.credsType, | ||||||
|  |             MavenPublishingRepository.CredentialsType.HttpHeaderCredentials( | ||||||
|  |                 "Authorization", | ||||||
|  |                 MavenPublishingRepository.CredentialsType.HttpHeaderCredentials.defaultValueProperty(item.name) | ||||||
|  |             ).takeIf { item.credsType !is MavenPublishingRepository.CredentialsType.HttpHeaderCredentials } ?: item.credsType, | ||||||
|  |         ) { | ||||||
|  |             with(credsTypesDrawer) { | ||||||
|  |                 with(it) { | ||||||
|  |                     draw() | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         DefaultContentColumn { | ||||||
|  |             when (val credsType = item.credsType) { | ||||||
|  |                 is MavenPublishingRepository.CredentialsType.HttpHeaderCredentials -> { | ||||||
|  |                     CommonText("Header name") | ||||||
|  |                     CommonTextField(credsType.headerName) { | ||||||
|  |                         item.credsType = credsType.copy(headerName = it) | ||||||
|  |                     } | ||||||
|  |                     DefaultSmallVerticalMargin() | ||||||
|  |  | ||||||
|  |                     CommonText("Property name") | ||||||
|  |                     CommonTextField(credsType.headerValueProperty) { | ||||||
|  |                         item.credsType = credsType.copy(headerValueProperty = it) | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 MavenPublishingRepository.CredentialsType.Nothing -> { | ||||||
|  |                     CommonText("No parameters for absence of credentials") | ||||||
|  |                 } | ||||||
|  |                 is MavenPublishingRepository.CredentialsType.UsernameAndPassword -> { | ||||||
|  |                     CommonText("Username property name") | ||||||
|  |                     CommonTextField(credsType.usernameProperty) { | ||||||
|  |                         item.credsType = credsType.copy(usernameProperty = it) | ||||||
|  |                     } | ||||||
|  |                     DefaultSmallVerticalMargin() | ||||||
|  |  | ||||||
|  |                     CommonText("Password property name") | ||||||
|  |                     CommonTextField(credsType.passwordProperty) { | ||||||
|  |                         item.credsType = credsType.copy(passwordProperty = it) | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -0,0 +1,14 @@ | |||||||
|  | package dev.inmo.kmppscriptbuilder.core.ui | ||||||
|  |  | ||||||
|  | import androidx.compose.runtime.Composable | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.DefaultContentColumn | ||||||
|  |  | ||||||
|  | abstract class VerticalView(protected val title: String) : View() { | ||||||
|  |     abstract val content: @Composable () -> Unit | ||||||
|  |     @Composable | ||||||
|  |     override fun build() { | ||||||
|  |         DefaultContentColumn { | ||||||
|  |             DrawVertically(title, content) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,16 @@ | |||||||
|  | package dev.inmo.kmppscriptbuilder.core.ui | ||||||
|  |  | ||||||
|  | import androidx.compose.runtime.Composable | ||||||
|  |  | ||||||
|  | expect abstract class View() { | ||||||
|  |     @Composable | ||||||
|  |     abstract fun build() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @Composable | ||||||
|  | expect fun View.DrawVertically(title: String, block: @Composable () -> Unit) | ||||||
|  |  | ||||||
|  | @Composable | ||||||
|  | fun <T : View> T.init(): T = apply { | ||||||
|  |     build() | ||||||
|  | } | ||||||
| @@ -0,0 +1,8 @@ | |||||||
|  | package dev.inmo.kmppscriptbuilder.core.ui.utils | ||||||
|  |  | ||||||
|  | import androidx.compose.runtime.Composable | ||||||
|  |  | ||||||
|  | fun interface Drawer<T> { | ||||||
|  |     @Composable | ||||||
|  |     fun T.draw() | ||||||
|  | } | ||||||
| @@ -0,0 +1,49 @@ | |||||||
|  | package dev.inmo.kmppscriptbuilder.core.ui.utils | ||||||
|  |  | ||||||
|  | import androidx.compose.runtime.Composable | ||||||
|  |  | ||||||
|  | @Composable | ||||||
|  | expect fun TitleText(text: String) | ||||||
|  |  | ||||||
|  | @Composable | ||||||
|  | expect fun CommonText(text: String, onClick: (() -> Unit)? = null) | ||||||
|  |  | ||||||
|  | @Composable | ||||||
|  | expect fun CommonTextField( | ||||||
|  |     presetText: String, | ||||||
|  |     hint: String? = null, | ||||||
|  |     onFocusChanged: (Boolean) -> Unit = {}, | ||||||
|  |     onChange: (String) -> Unit | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | @Composable | ||||||
|  | expect fun SwitchWithLabel( | ||||||
|  |     label: String, | ||||||
|  |     checked: Boolean, | ||||||
|  |     placeSwitchAtTheStart: Boolean = false, | ||||||
|  |     switchEnabled: Boolean = true, | ||||||
|  |     onCheckedChange: (Boolean) -> Unit | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | @Composable | ||||||
|  | expect fun <T> ButtonsPanel( | ||||||
|  |     title: String, | ||||||
|  |     data: Iterable<T>, | ||||||
|  |     itemDrawer: @Composable (T) -> Unit | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | @Composable | ||||||
|  | fun <T> ButtonsPanel( | ||||||
|  |     title: String, | ||||||
|  |     vararg data: T, | ||||||
|  |     itemDrawer: @Composable (T) -> Unit | ||||||
|  | ) = ButtonsPanel(title, data.toList(), itemDrawer) | ||||||
|  |  | ||||||
|  | @Composable | ||||||
|  | expect fun DefaultDivider() | ||||||
|  |  | ||||||
|  | @Composable | ||||||
|  | expect fun DefaultSmallVerticalMargin() | ||||||
|  |  | ||||||
|  | @Composable | ||||||
|  | expect fun DefaultContentColumn(block: @Composable () -> Unit) | ||||||
| @@ -0,0 +1,14 @@ | |||||||
|  | package dev.inmo.kmppscriptbuilder.core.utils | ||||||
|  |  | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.models.Config | ||||||
|  | import dev.inmo.micro_utils.common.MPPFile | ||||||
|  |  | ||||||
|  | internal const val appExtension = "kpsb" | ||||||
|  |  | ||||||
|  | expect fun openNewConfig(onParsed: (Config) -> Unit) | ||||||
|  |  | ||||||
|  | expect fun saveConfig(config: Config): Boolean | ||||||
|  |  | ||||||
|  | expect fun exportGradle(config: Config): Boolean | ||||||
|  |  | ||||||
|  | expect fun saveAs(config: Config): Boolean | ||||||
| @@ -0,0 +1,3 @@ | |||||||
|  | package dev.inmo.kmppscriptbuilder.core.utils | ||||||
|  |  | ||||||
|  | expect fun openLink(link: String): Boolean | ||||||
| Before Width: | Height: | Size: 463 B After Width: | Height: | Size: 463 B | 
| Before Width: | Height: | Size: 452 B After Width: | Height: | Size: 452 B | 
| Before Width: | Height: | Size: 744 B After Width: | Height: | Size: 744 B | 
| Before Width: | Height: | Size: 502 B After Width: | Height: | Size: 502 B | 
| @@ -0,0 +1,14 @@ | |||||||
|  | package dev.inmo.kmppscriptbuilder.core | ||||||
|  |  | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.BuilderView | ||||||
|  | import kotlinx.browser.window | ||||||
|  | import org.jetbrains.compose.web.renderComposableInBody | ||||||
|  |  | ||||||
|  | fun main() { | ||||||
|  |     window.addEventListener("load", { | ||||||
|  |         val builder = BuilderView() | ||||||
|  |         renderComposableInBody { | ||||||
|  |             builder.build() | ||||||
|  |         } | ||||||
|  |     }) | ||||||
|  | } | ||||||
| @@ -0,0 +1,35 @@ | |||||||
|  | package dev.inmo.kmppscriptbuilder.core.ui | ||||||
|  |  | ||||||
|  | import androidx.compose.runtime.Composable | ||||||
|  | import dev.inmo.jsuikit.elements.DefaultButton | ||||||
|  | import dev.inmo.jsuikit.modifiers.UIKitButton | ||||||
|  | import dev.inmo.jsuikit.modifiers.UIKitMargin | ||||||
|  | import dev.inmo.jsuikit.modifiers.UIKitTooltipModifier | ||||||
|  | import dev.inmo.jsuikit.modifiers.UIKitUtility | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.models.GpgSigning | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.Drawer | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.NoTransform | ||||||
|  |  | ||||||
|  | actual class GpgSigningOptionDrawer( | ||||||
|  |     private val mavenInfoView: MavenInfoView | ||||||
|  | ) : Drawer<GpgSigning> { | ||||||
|  |     @Composable | ||||||
|  |     override fun GpgSigning.draw() { | ||||||
|  |         val tooltipModifier = UIKitTooltipModifier( | ||||||
|  |             when (this) { | ||||||
|  |                 GpgSigning.Disabled -> "Signing will not be added" | ||||||
|  |                 GpgSigning.Enabled -> "Signing will be always enabled" | ||||||
|  |                 GpgSigning.Optional -> "Signing will be added, but disabled in case of absence 'signatory.keyId'" | ||||||
|  |             } | ||||||
|  |         ) | ||||||
|  |         if (mavenInfoView.gpgSignProperty == this) { | ||||||
|  |             DefaultButton(name, UIKitButton.Type.Primary, UIKitButton.Size.Small, UIKitMargin.Small.Horizontal, UIKitUtility.NoTransform, UIKitUtility.Border.Rounded, tooltipModifier) | ||||||
|  |         } else { | ||||||
|  |             DefaultButton(name, UIKitButton.Type.Default, UIKitButton.Size.Small, UIKitMargin.Small.Horizontal, UIKitUtility.NoTransform, UIKitUtility.Border.Rounded, tooltipModifier) { | ||||||
|  |                 mavenInfoView.gpgSignProperty = this | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | actual fun GpgSigningOptionDrawerWithView(view: MavenInfoView): GpgSigningOptionDrawer = GpgSigningOptionDrawer(mavenInfoView = view) | ||||||
| @@ -0,0 +1,37 @@ | |||||||
|  | package dev.inmo.kmppscriptbuilder.core.ui | ||||||
|  |  | ||||||
|  | import androidx.compose.runtime.Composable | ||||||
|  | import dev.inmo.jsuikit.elements.DefaultButton | ||||||
|  | import dev.inmo.jsuikit.elements.Divider | ||||||
|  | import dev.inmo.jsuikit.modifiers.UIKitButton | ||||||
|  | import dev.inmo.jsuikit.modifiers.UIKitMargin | ||||||
|  | import dev.inmo.jsuikit.modifiers.UIKitUtility | ||||||
|  | import dev.inmo.jsuikit.modifiers.builder | ||||||
|  | import dev.inmo.jsuikit.utils.Attrs | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.CommonTextField | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.Drawer | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.NoTransform | ||||||
|  | import org.jetbrains.compose.web.dom.Div | ||||||
|  |  | ||||||
|  | actual object LicensesDrawer : Drawer<LicensesView> { | ||||||
|  |     @Composable | ||||||
|  |     override fun LicensesView.draw() { | ||||||
|  |         dev.inmo.jsuikit.elements.List( | ||||||
|  |             licensesOffersToShow.value, | ||||||
|  |             Attrs { | ||||||
|  |                 if (!searchFieldFocused.value) { | ||||||
|  |                     hidden() | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         ) { | ||||||
|  |             DefaultButton( | ||||||
|  |                 it.title, | ||||||
|  |                 UIKitButton.Type.Text | ||||||
|  |             ) { _ -> | ||||||
|  |                 itemsList.add(it.toLicenseState()) | ||||||
|  |                 licenseSearchFilter = "" | ||||||
|  |             } | ||||||
|  |             Divider.Common() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,28 @@ | |||||||
|  | package dev.inmo.kmppscriptbuilder.core.ui | ||||||
|  |  | ||||||
|  | import androidx.compose.runtime.Composable | ||||||
|  | import dev.inmo.jsuikit.elements.DefaultButton | ||||||
|  | import dev.inmo.jsuikit.modifiers.UIKitButton | ||||||
|  | import dev.inmo.jsuikit.modifiers.UIKitMargin | ||||||
|  | import dev.inmo.jsuikit.modifiers.UIKitUtility | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.DefaultContentColumn | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.Drawer | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.NoTransform | ||||||
|  |  | ||||||
|  | actual class ListViewDrawer<T> : Drawer<ListView<T>> { | ||||||
|  |     @Composable | ||||||
|  |     override fun ListView<T>.draw() { | ||||||
|  |         itemsList.forEach { item -> | ||||||
|  |             DefaultContentColumn { | ||||||
|  |                 buildView(item) | ||||||
|  |                 DefaultButton(removeItemText, UIKitButton.Type.Default, UIKitMargin.Small, UIKitUtility.NoTransform, UIKitUtility.Border.Rounded) { | ||||||
|  |                     itemsList.remove(item) | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             DefaultButton(addItemText, UIKitButton.Type.Primary, UIKitUtility.NoTransform, UIKitUtility.Border.Rounded ) { itemsList.add(createItem()) } | ||||||
|  |         } | ||||||
|  |         if (itemsList.isEmpty()) { | ||||||
|  |             DefaultButton(addItemText, UIKitButton.Type.Primary, UIKitUtility.NoTransform, UIKitUtility.Border.Rounded ) { itemsList.add(createItem()) } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,28 @@ | |||||||
|  | package dev.inmo.kmppscriptbuilder.core.ui | ||||||
|  |  | ||||||
|  | import androidx.compose.runtime.Composable | ||||||
|  | import dev.inmo.jsuikit.elements.DefaultButton | ||||||
|  | import dev.inmo.jsuikit.modifiers.UIKitButton | ||||||
|  | import dev.inmo.jsuikit.modifiers.UIKitMargin | ||||||
|  | import dev.inmo.jsuikit.modifiers.UIKitText | ||||||
|  | import dev.inmo.jsuikit.modifiers.UIKitUtility | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.models.ProjectType | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.Drawer | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.NoTransform | ||||||
|  |  | ||||||
|  | actual class ProjectTypeDrawer( | ||||||
|  |     private val projectTypeView: ProjectTypeView | ||||||
|  | ) : Drawer<ProjectType> { | ||||||
|  |     @Composable | ||||||
|  |     override fun ProjectType.draw() { | ||||||
|  |         if (projectTypeView.projectType == this) { | ||||||
|  |             DefaultButton(name, UIKitButton.Type.Primary, UIKitButton.Size.Small, UIKitMargin.Small.Horizontal, UIKitUtility.NoTransform, UIKitUtility.Border.Rounded) | ||||||
|  |         } else { | ||||||
|  |             DefaultButton(name, UIKitButton.Type.Default, UIKitButton.Size.Small, UIKitMargin.Small.Horizontal, UIKitUtility.NoTransform, UIKitUtility.Border.Rounded) { | ||||||
|  |                 projectTypeView.projectType = this | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | actual fun ProjectTypeDrawerWithView(view: ProjectTypeView): ProjectTypeDrawer = ProjectTypeDrawer(projectTypeView = view) | ||||||
| @@ -0,0 +1,32 @@ | |||||||
|  | package dev.inmo.kmppscriptbuilder.core.ui | ||||||
|  |  | ||||||
|  | import androidx.compose.runtime.Composable | ||||||
|  | import dev.inmo.jsuikit.elements.DefaultButton | ||||||
|  | import dev.inmo.jsuikit.modifiers.UIKitButton | ||||||
|  | import dev.inmo.jsuikit.modifiers.UIKitMargin | ||||||
|  | import dev.inmo.jsuikit.modifiers.UIKitUtility | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.models.MavenPublishingRepository | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.Drawer | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.NoTransform | ||||||
|  |  | ||||||
|  | actual class RepositoryCredentialTypeDrawer( | ||||||
|  |     private val state: RepositoryState | ||||||
|  | ) : Drawer<MavenPublishingRepository.CredentialsType> { | ||||||
|  |     @Composable | ||||||
|  |     override fun MavenPublishingRepository.CredentialsType.draw() { | ||||||
|  |         val name = when (this@draw) { | ||||||
|  |             is MavenPublishingRepository.CredentialsType.HttpHeaderCredentials -> "Headers" | ||||||
|  |             MavenPublishingRepository.CredentialsType.Nothing -> "No" | ||||||
|  |             is MavenPublishingRepository.CredentialsType.UsernameAndPassword -> "Username and password" | ||||||
|  |         } | ||||||
|  |         if (state.credsType == this) { | ||||||
|  |             DefaultButton(name, UIKitButton.Type.Primary, UIKitButton.Size.Small, UIKitMargin.Small.Horizontal, UIKitUtility.NoTransform, UIKitUtility.Border.Rounded) | ||||||
|  |         } else { | ||||||
|  |             DefaultButton(name, UIKitButton.Type.Default, UIKitButton.Size.Small, UIKitMargin.Small.Horizontal, UIKitUtility.NoTransform, UIKitUtility.Border.Rounded) { | ||||||
|  |                 state.credsType = this | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | actual fun RepositoryCredentialTypeDrawerWithState(repositoryState: RepositoryState): RepositoryCredentialTypeDrawer = RepositoryCredentialTypeDrawer(repositoryState) | ||||||
| @@ -0,0 +1,92 @@ | |||||||
|  | package dev.inmo.kmppscriptbuilder.core.ui | ||||||
|  |  | ||||||
|  | import androidx.compose.runtime.Composable | ||||||
|  | import dev.inmo.jsuikit.elements.Icon | ||||||
|  | import dev.inmo.jsuikit.elements.NavItemElement | ||||||
|  | import dev.inmo.jsuikit.elements.Navbar | ||||||
|  | import dev.inmo.jsuikit.elements.NavbarNav | ||||||
|  | import dev.inmo.jsuikit.elements.drawAsLink | ||||||
|  | import dev.inmo.jsuikit.modifiers.UIKitBackground | ||||||
|  | import dev.inmo.jsuikit.modifiers.UIKitInverse | ||||||
|  | import dev.inmo.jsuikit.modifiers.UIKitMargin | ||||||
|  | import dev.inmo.jsuikit.modifiers.UIKitModifier | ||||||
|  | import dev.inmo.jsuikit.modifiers.UIKitNavbar | ||||||
|  | import dev.inmo.jsuikit.modifiers.UIKitPadding | ||||||
|  | import dev.inmo.jsuikit.modifiers.UIKitSection | ||||||
|  | import dev.inmo.jsuikit.modifiers.UIKitText | ||||||
|  | import dev.inmo.jsuikit.modifiers.UIKitTooltipModifier | ||||||
|  | import dev.inmo.jsuikit.modifiers.attrsBuilder | ||||||
|  | import dev.inmo.jsuikit.modifiers.builder | ||||||
|  | import dev.inmo.jsuikit.modifiers.include | ||||||
|  | import dev.inmo.jsuikit.utils.AttrsWithContentBuilder | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.models.Config | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.utils.exportGradle | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.utils.openNewConfig | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.utils.saveConfig | ||||||
|  | import org.jetbrains.compose.web.dom.A | ||||||
|  | import org.jetbrains.compose.web.dom.Div | ||||||
|  | import org.jetbrains.compose.web.dom.Img | ||||||
|  | import org.jetbrains.compose.web.dom.Section | ||||||
|  | import org.jetbrains.compose.web.dom.Text | ||||||
|  |  | ||||||
|  | @Composable | ||||||
|  | actual fun TopAppBar( | ||||||
|  |     config: Config, | ||||||
|  |     saveAvailable: Boolean, | ||||||
|  |     onSaveAvailable: (Boolean) -> Unit, | ||||||
|  |     onNewConfig: (Config) -> Unit | ||||||
|  | ) { | ||||||
|  |     Section(attrsBuilder(UIKitSection.Style.Primary, UIKitInverse.Light)) { | ||||||
|  |         Navbar( | ||||||
|  |             leftBuilder = AttrsWithContentBuilder { | ||||||
|  |                 Div( | ||||||
|  |                     { | ||||||
|  |                         onClick { | ||||||
|  |                             console.log(config) | ||||||
|  |                         } | ||||||
|  |                         include(UIKitPadding.Size.Small, UIKitText.Style.Lead) | ||||||
|  |                     } | ||||||
|  |                 ) { | ||||||
|  |                     Text("Kotlin publication scripts builder") | ||||||
|  |                 } | ||||||
|  |                 Div(UIKitMargin.Small.builder()) { | ||||||
|  |                     A("https://github.com/InsanusMokrassar/KotlinPublicationScriptsBuilder") { | ||||||
|  |                         Img("https://img.shields.io/github/stars/InsanusMokrassar/KotlinPublicationScriptsBuilder?label=Github&style=plastic") | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             }, | ||||||
|  |             rightBuilder = AttrsWithContentBuilder { | ||||||
|  |                 NavbarNav( | ||||||
|  |                     AttrsWithContentBuilder { | ||||||
|  |                         NavItemElement( | ||||||
|  |                             UIKitTooltipModifier("Open file") | ||||||
|  |                         ) { | ||||||
|  |                             Icon.Storage.Pull.drawAsLink { | ||||||
|  |                                 openNewConfig(onNewConfig) | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  |                     }, | ||||||
|  |                     AttrsWithContentBuilder { | ||||||
|  |                         NavItemElement( | ||||||
|  |                             UIKitTooltipModifier("Save config") | ||||||
|  |                         ) { | ||||||
|  |                             Icon.Storage.Push.drawAsLink { | ||||||
|  |                                 saveConfig(config) | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  |                     }, | ||||||
|  |                     AttrsWithContentBuilder { | ||||||
|  |                         NavItemElement( | ||||||
|  |                             UIKitTooltipModifier("Export gradle script") | ||||||
|  |                         ) { | ||||||
|  |                             Icon.Storage.Upload.drawAsLink { | ||||||
|  |                                 exportGradle(config) | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  |                     }, | ||||||
|  |                 ) | ||||||
|  |             }, | ||||||
|  |             navModifiers = arrayOf(UIKitNavbar.Transparent) | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,23 @@ | |||||||
|  | package dev.inmo.kmppscriptbuilder.core.ui | ||||||
|  |  | ||||||
|  | import androidx.compose.runtime.Composable | ||||||
|  | import dev.inmo.jsuikit.modifiers.UIKitForm | ||||||
|  | import dev.inmo.jsuikit.modifiers.builder | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.DefaultSmallVerticalMargin | ||||||
|  | import org.jetbrains.compose.web.dom.Legend | ||||||
|  | import org.jetbrains.compose.web.dom.Text | ||||||
|  |  | ||||||
|  | actual abstract class View { | ||||||
|  |     @Composable | ||||||
|  |     actual abstract fun build() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @Composable | ||||||
|  | actual fun View.DrawVertically(title: String, block: @Composable () -> Unit) { | ||||||
|  |     Legend(UIKitForm.Legend.builder()) { | ||||||
|  |         Text(title) | ||||||
|  |     } | ||||||
|  |     DefaultSmallVerticalMargin() | ||||||
|  |     block() | ||||||
|  |     DefaultSmallVerticalMargin() | ||||||
|  | } | ||||||
| @@ -0,0 +1,128 @@ | |||||||
|  | package dev.inmo.kmppscriptbuilder.core.ui.utils | ||||||
|  |  | ||||||
|  | import androidx.compose.runtime.Composable | ||||||
|  | import dev.inmo.jsuikit.elements.DefaultButton | ||||||
|  | import dev.inmo.jsuikit.elements.DefaultInput | ||||||
|  | import dev.inmo.jsuikit.elements.Divider | ||||||
|  | import dev.inmo.jsuikit.elements.Flex | ||||||
|  | import dev.inmo.jsuikit.elements.Icon | ||||||
|  | import dev.inmo.jsuikit.elements.drawAsFormInputPart | ||||||
|  | import dev.inmo.jsuikit.modifiers.UIKitButton | ||||||
|  | import dev.inmo.jsuikit.modifiers.UIKitFlex | ||||||
|  | import dev.inmo.jsuikit.modifiers.UIKitForm | ||||||
|  | import dev.inmo.jsuikit.modifiers.UIKitInverse | ||||||
|  | import dev.inmo.jsuikit.modifiers.UIKitMargin | ||||||
|  | import dev.inmo.jsuikit.modifiers.UIKitUtility | ||||||
|  | import dev.inmo.jsuikit.modifiers.attrsBuilder | ||||||
|  | import dev.inmo.jsuikit.modifiers.builder | ||||||
|  | import dev.inmo.jsuikit.modifiers.include | ||||||
|  | import kotlinx.browser.window | ||||||
|  | import org.jetbrains.compose.web.attributes.InputType | ||||||
|  | import org.jetbrains.compose.web.dom.Div | ||||||
|  | import org.jetbrains.compose.web.dom.Legend | ||||||
|  | import org.jetbrains.compose.web.dom.Text | ||||||
|  |  | ||||||
|  | @Composable | ||||||
|  | actual fun TitleText(text: String) { | ||||||
|  |     Legend(UIKitForm.Legend.builder()) { | ||||||
|  |         Text(text) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @Composable | ||||||
|  | actual fun CommonText(text: String, onClick: (() -> Unit)?) { | ||||||
|  |     Div( | ||||||
|  |         { | ||||||
|  |             onClick ?.let { | ||||||
|  |                 this.onClick { _ -> | ||||||
|  |                     it() | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     ) { | ||||||
|  |         Text(text) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @Composable | ||||||
|  | actual fun CommonTextField( | ||||||
|  |     presetText: String, | ||||||
|  |     hint: String?, | ||||||
|  |     onFocusChanged: (Boolean) -> Unit, | ||||||
|  |     onChange: (String) -> Unit | ||||||
|  | ) { | ||||||
|  |     DefaultInput( | ||||||
|  |         InputType.Text, | ||||||
|  |         presetText, | ||||||
|  |         false, | ||||||
|  |         placeholder = hint, | ||||||
|  |         attributesCustomizer = { | ||||||
|  |             onFocusIn { onFocusChanged(true) } | ||||||
|  |             onFocusOut { | ||||||
|  |                 window.setTimeout( // avoid immediate hiding of potential interface data with additional delay | ||||||
|  |                     { onFocusChanged(false) }, | ||||||
|  |                     100 | ||||||
|  |                 ) | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         onChange = onChange | ||||||
|  |     ) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @Composable | ||||||
|  | actual fun SwitchWithLabel( | ||||||
|  |     label: String, | ||||||
|  |     checked: Boolean, | ||||||
|  |     placeSwitchAtTheStart: Boolean, | ||||||
|  |     switchEnabled: Boolean, | ||||||
|  |     onCheckedChange: (Boolean) -> Unit | ||||||
|  | ) { | ||||||
|  |     DefaultButton( | ||||||
|  |         if (checked) { | ||||||
|  |             UIKitButton.Type.Primary | ||||||
|  |         } else { | ||||||
|  |             UIKitButton.Type.Default | ||||||
|  |         }, | ||||||
|  |         disabled = !switchEnabled, | ||||||
|  |         onClick = { | ||||||
|  |             onCheckedChange(!checked) | ||||||
|  |         }, | ||||||
|  |         attributesCustomizer = { | ||||||
|  |             include(UIKitUtility.Inline, UIKitUtility.NoTransform, UIKitUtility.Border.Rounded) | ||||||
|  |         } | ||||||
|  |     ) { | ||||||
|  |         if (checked) { | ||||||
|  |             Icon.App.Check.drawAsFormInputPart(UIKitInverse.Light) | ||||||
|  |         } | ||||||
|  |         Text(label) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @Composable | ||||||
|  | actual fun <T> ButtonsPanel( | ||||||
|  |     title: String, | ||||||
|  |     data: Iterable<T>, | ||||||
|  |     itemDrawer: @Composable (T) -> Unit | ||||||
|  | ) { | ||||||
|  |     Flex(UIKitFlex.Alignment.Vertical.Middle, UIKitMargin.Small) { | ||||||
|  |         Div(UIKitMargin.Small.Horizontal.builder()) { Text(title) } | ||||||
|  |         data.forEach { itemDrawer(it) } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @Composable | ||||||
|  | actual fun DefaultDivider() { | ||||||
|  |     Divider.Common() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @Composable | ||||||
|  | actual fun DefaultSmallVerticalMargin() { | ||||||
|  |     Div(UIKitMargin.Small.Top.builder()) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @Composable | ||||||
|  | actual fun DefaultContentColumn(block: @Composable () -> Unit) { | ||||||
|  |     Div(attrsBuilder(UIKitMargin.Small.Horizontal, UIKitMargin.Small.Vertical)) { | ||||||
|  |         block() | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,9 @@ | |||||||
|  | package dev.inmo.kmppscriptbuilder.core.ui.utils | ||||||
|  |  | ||||||
|  | import dev.inmo.jsuikit.modifiers.UIKitCustom | ||||||
|  | import dev.inmo.jsuikit.modifiers.UIKitUtility | ||||||
|  |  | ||||||
|  | val ClassNoTransform = UIKitCustom(arrayOf("no-transform")) | ||||||
|  |  | ||||||
|  | val UIKitUtility.Companion.NoTransform | ||||||
|  |     get() = ClassNoTransform | ||||||
| @@ -0,0 +1,83 @@ | |||||||
|  | package dev.inmo.kmppscriptbuilder.core.utils | ||||||
|  |  | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.models.Config | ||||||
|  | import kotlinx.browser.document | ||||||
|  | import kotlinx.dom.appendElement | ||||||
|  | import org.w3c.dom.HTMLAnchorElement | ||||||
|  | import org.w3c.dom.HTMLInputElement | ||||||
|  | import org.w3c.dom.url.URL | ||||||
|  | import org.w3c.files.Blob | ||||||
|  | import org.w3c.files.BlobPropertyBag | ||||||
|  | import org.w3c.files.FileReader | ||||||
|  | import org.w3c.files.get | ||||||
|  |  | ||||||
|  | fun saveFile(content: String, filename: String) { | ||||||
|  |     val a = document.body!!.appendElement("a") { | ||||||
|  |         setAttribute("style", "visibility:hidden; display: none") | ||||||
|  |     } as HTMLAnchorElement | ||||||
|  |     val blob = Blob(arrayOf(content), BlobPropertyBag( | ||||||
|  |         "application/*;charset=utf-8" | ||||||
|  |     )) | ||||||
|  |     val url = URL.createObjectURL(blob) | ||||||
|  |     a.href = url | ||||||
|  |     a.download = filename | ||||||
|  |     a.click() | ||||||
|  |     URL.revokeObjectURL(url) | ||||||
|  |     a.remove() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | actual fun openNewConfig(onParsed: (Config) -> Unit) { | ||||||
|  |     val targetInput = document.body!!.appendElement("input") { | ||||||
|  |         setAttribute("style", "visibility:hidden; display: none") | ||||||
|  |     } as HTMLInputElement | ||||||
|  |     targetInput.type = "file" | ||||||
|  |     targetInput.onchange = { | ||||||
|  |         targetInput.files ?.also { files -> | ||||||
|  |             for (i in (0 until files.length) ) { | ||||||
|  |                 files[i] ?.also { file -> | ||||||
|  |                     val reader = FileReader() | ||||||
|  |  | ||||||
|  |                     reader.onload = { | ||||||
|  |                         val content = it.target.asDynamic().result as String | ||||||
|  |                         onParsed(serialFormat.decodeFromString(Config.serializer(), content)) | ||||||
|  |                         false | ||||||
|  |                     } | ||||||
|  |  | ||||||
|  |                     reader.readAsText(file) | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     targetInput.click() | ||||||
|  |     targetInput.remove() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | actual fun saveConfig(config: Config): Boolean { | ||||||
|  |     saveFile( | ||||||
|  |         serialFormat.encodeToString(Config.serializer(), config), | ||||||
|  |         "publish.kpsb" | ||||||
|  |     ) | ||||||
|  |     return true | ||||||
|  | } | ||||||
|  |  | ||||||
|  | actual fun exportGradle(config: Config): Boolean { | ||||||
|  |     val filename = "publish.gradle" | ||||||
|  |  | ||||||
|  |     val content = config.run { | ||||||
|  |         type.buildMavenGradleConfig( | ||||||
|  |             mavenConfig, | ||||||
|  |             licenses | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     saveFile(content, filename) | ||||||
|  |     return true | ||||||
|  | } | ||||||
|  |  | ||||||
|  | actual fun saveAs(config: Config): Boolean { | ||||||
|  |     saveFile( | ||||||
|  |         serialFormat.encodeToString(Config.serializer(), config), | ||||||
|  |         "publish.kpsb" | ||||||
|  |     ) | ||||||
|  |     return true | ||||||
|  | } | ||||||
| @@ -0,0 +1,6 @@ | |||||||
|  | package dev.inmo.kmppscriptbuilder.core.utils | ||||||
|  |  | ||||||
|  | actual fun openLink(link: String): Boolean { | ||||||
|  |     dev.inmo.micro_utils.common.openLink(link) | ||||||
|  |     return true | ||||||
|  | } | ||||||
							
								
								
									
										4
									
								
								core/src/jsMain/resources/css/internal.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,4 @@ | |||||||
|  | .no-transform { | ||||||
|  |     text-transform: none; | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										1
									
								
								core/src/jsMain/resources/css/uikit.min.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										73
									
								
								core/src/jsMain/resources/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,73 @@ | |||||||
|  | <!DOCTYPE html> | ||||||
|  | <html lang="en"> | ||||||
|  | <head> | ||||||
|  |     <meta charset="UTF-8"> | ||||||
|  |     <title>Kotlin Publication Scripts Builder</title> | ||||||
|  |     <!-- UIkit CSS --> | ||||||
|  |     <link rel="stylesheet" href="./css/uikit.min.css" /> | ||||||
|  |     <link rel="stylesheet" href="./css/internal.css" /> | ||||||
|  | </head> | ||||||
|  | <body> | ||||||
|  | <!--    <form class="uk-padding-small">--> | ||||||
|  | <!--        <fieldset class="uk-fieldset">--> | ||||||
|  | <!--            <legend class="uk-legend">Project type</legend>--> | ||||||
|  | <!--            <div class="uk-padding-small">--> | ||||||
|  | <!--                <ul class="uk-subnav uk-subnav-pill">--> | ||||||
|  | <!--                    <li id="mppProjectType" class="uk-active"><a href="#">Multiplatform</a></li>--> | ||||||
|  | <!--                    <li id="jvmProjectType"><a href="#">JVM</a></li>--> | ||||||
|  | <!--                    <li id="jsProjectType"><a href="#">JS</a></li>--> | ||||||
|  | <!--                </ul>--> | ||||||
|  | <!--            </div>--> | ||||||
|  | <!--            <legend class="uk-legend">Licenses</legend>--> | ||||||
|  | <!--            <div id="licensesListDiv" class="uk-padding-small"></div>--> | ||||||
|  |  | ||||||
|  | <!--            <legend class="uk-legend">Project information</legend>--> | ||||||
|  |  | ||||||
|  | <!--            <div class="uk-padding-small">--> | ||||||
|  | <!--                <div class="uk-margin uk-width-1-1">--> | ||||||
|  | <!--                    <label class="uk-form-label" for="projectNameInput">Public project name</label>--> | ||||||
|  | <!--                    <input id="projectNameInput" class="uk-input uk-width-expand" type="text" placeholder="${project.name}">--> | ||||||
|  | <!--                </div>--> | ||||||
|  | <!--                <div class="uk-margin uk-width-1-1">--> | ||||||
|  | <!--                    <label class="uk-form-label" for="projectDescriptionInput">Public project description</label>--> | ||||||
|  | <!--                    <input id="projectDescriptionInput" class="uk-input uk-width-expand" type="text" placeholder="${project.name}">--> | ||||||
|  | <!--                </div>--> | ||||||
|  | <!--                <div class="uk-margin uk-width-1-1">--> | ||||||
|  | <!--                    <label class="uk-form-label" for="projectUrlInput">Public project URL</label>--> | ||||||
|  | <!--                    <input id="projectUrlInput" class="uk-input uk-width-expand" type="text" placeholder="Type url to github or other source with readme">--> | ||||||
|  | <!--                </div>--> | ||||||
|  | <!--                <div class="uk-margin uk-width-1-1">--> | ||||||
|  | <!--                    <label class="uk-form-label" for="projectVCSUrlInput">Public project VCS URL (with .git)</label>--> | ||||||
|  | <!--                    <input id="projectVCSUrlInput" class="uk-input uk-width-expand" type="text" placeholder="Type url to github .git file">--> | ||||||
|  | <!--                </div>--> | ||||||
|  |  | ||||||
|  | <!--                <div class="uk-margin">--> | ||||||
|  | <!--                    <label>GPG Signing</label>--> | ||||||
|  |  | ||||||
|  | <!--                    <div class="uk-padding-small">--> | ||||||
|  | <!--                        <ul class="uk-subnav uk-subnav-pill">--> | ||||||
|  | <!--                            <li id="disableGpgSigning" class="uk-active" uk-tooltip="title: Signing will not be added"><a href="#">Disabled</a></li>--> | ||||||
|  | <!--                            <li id="optionalGpgSigning" uk-tooltip="title: Signing will be added, but disabled in case of absence 'signatory.keyId'"><a href="#">Optional</a></li>--> | ||||||
|  | <!--                            <li id="enableGpgSigning" uk-tooltip="title: Signing will be always enabled"><a href="#">Enabled</a></li>--> | ||||||
|  | <!--                        </ul>--> | ||||||
|  | <!--                    </div>--> | ||||||
|  | <!--                </div>--> | ||||||
|  | <!--                <div class="uk-margin">--> | ||||||
|  | <!--                    <label><input id="includeMavenCentralTargetRepoToggle" class="uk-checkbox" type="checkbox"> Include publication to MavenCentral</label>--> | ||||||
|  | <!--                </div>--> | ||||||
|  | <!--            </div>--> | ||||||
|  |  | ||||||
|  | <!--            <legend class="uk-legend">Developers info</legend>--> | ||||||
|  | <!--            <div id="developersListDiv" class="uk-padding-small"></div>--> | ||||||
|  |  | ||||||
|  | <!--            <legend class="uk-legend">Repositories info</legend>--> | ||||||
|  | <!--            <div id="repositoriesListDiv" class="uk-padding-small"></div>--> | ||||||
|  | <!--        </fieldset>--> | ||||||
|  | <!--    </form>--> | ||||||
|  |     <!-- UIkit JS --> | ||||||
|  |     <script src="./js/uikit.min.js"></script> | ||||||
|  |     <script src="./js/uikit-icons.min.js"></script> | ||||||
|  |     <!-- Internal JS --> | ||||||
|  |     <script src="kmppscriptbuilder.core.js"></script> | ||||||
|  | </body> | ||||||
|  | </html> | ||||||
							
								
								
									
										1
									
								
								core/src/jsMain/resources/js/uikit-icons.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										1
									
								
								core/src/jsMain/resources/js/uikit.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,68 @@ | |||||||
|  | package dev.inmo.kmppscriptbuilder.core | ||||||
|  |  | ||||||
|  | import androidx.compose.foundation.* | ||||||
|  | import androidx.compose.foundation.layout.* | ||||||
|  | import androidx.compose.material.Colors | ||||||
|  | import androidx.compose.material.MaterialTheme | ||||||
|  | import androidx.compose.ui.Alignment | ||||||
|  | import androidx.compose.ui.Modifier | ||||||
|  | import androidx.compose.ui.graphics.Color | ||||||
|  | import androidx.compose.ui.window.Window | ||||||
|  | import androidx.compose.ui.window.application | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.BuilderView | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.utils.loadConfigFile | ||||||
|  | import java.io.File | ||||||
|  |  | ||||||
|  | //private val uncaughtExceptionsBC = BroadcastChannel<DefaultErrorHandler.ErrorEvent>(Channel.CONFLATED) | ||||||
|  | //val uncaughtExceptionsFlow: Flow<DefaultErrorHandler.ErrorEvent> = uncaughtExceptionsBC.asFlow() | ||||||
|  |  | ||||||
|  | fun main(args: Array<String>) = application { | ||||||
|  |     Window(onCloseRequest = ::exitApplication, title = "Kotlin Multiplatform Publishing Builder") { | ||||||
|  |         val builder = BuilderView() | ||||||
|  |         MaterialTheme( | ||||||
|  |             Colors( | ||||||
|  |                 primary = Color(0x01, 0x57, 0x9b), | ||||||
|  |                 primaryVariant = Color(0x00, 0x2f, 0x6c), | ||||||
|  |                 secondary = Color(0xb2, 0xeb, 0xf2), | ||||||
|  |                 secondaryVariant = Color(0x81, 0xb9, 0xbf), | ||||||
|  |                 background = Color(0xe1, 0xe2, 0xe1), | ||||||
|  |                 surface = Color(0xf5, 0xf5, 0xf6), | ||||||
|  |                 error = Color(0xb7, 0x1c, 0x1c), | ||||||
|  |                 onPrimary = Color.White, | ||||||
|  |                 onSecondary = Color.Black, | ||||||
|  |                 onBackground = Color.Black, | ||||||
|  |                 onSurface = Color.Black, | ||||||
|  |                 onError = Color.White, | ||||||
|  |                 isLight = MaterialTheme.colors.isLight, | ||||||
|  |             ) | ||||||
|  |         ) { | ||||||
|  |             Box( | ||||||
|  |                 Modifier.fillMaxSize() | ||||||
|  |                     .background(color = Color(245, 245, 245)) | ||||||
|  |             ) { | ||||||
|  |  | ||||||
|  |                 val stateVertical = rememberScrollState(0) | ||||||
|  |                 Box( | ||||||
|  |                     modifier = Modifier | ||||||
|  |                         .fillMaxSize() | ||||||
|  |                         .verticalScroll(stateVertical) | ||||||
|  |                 ) { | ||||||
|  |                     Column { | ||||||
|  |                         builder.build() | ||||||
|  |                     } | ||||||
|  |  | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 VerticalScrollbar( | ||||||
|  |                     modifier = Modifier.align(Alignment.CenterEnd).fillMaxHeight(), | ||||||
|  |                     adapter = rememberScrollbarAdapter(stateVertical) | ||||||
|  |                 ) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (args.isNotEmpty()) { | ||||||
|  |             val config = loadConfigFile(File(args.first())) | ||||||
|  |             builder.config = config | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,33 @@ | |||||||
|  | package dev.inmo.kmppscriptbuilder.core.ui | ||||||
|  |  | ||||||
|  | import androidx.compose.foundation.layout.Column | ||||||
|  | import androidx.compose.foundation.layout.Spacer | ||||||
|  | import androidx.compose.foundation.layout.fillMaxWidth | ||||||
|  | import androidx.compose.foundation.layout.height | ||||||
|  | import androidx.compose.foundation.layout.padding | ||||||
|  | import androidx.compose.runtime.Composable | ||||||
|  | import androidx.compose.ui.Modifier | ||||||
|  | import androidx.compose.ui.unit.dp | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.DefaultSmallVerticalMargin | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.TitleText | ||||||
|  |  | ||||||
|  | actual abstract class View { | ||||||
|  |     internal open val defaultModifier = Modifier.fillMaxWidth() | ||||||
|  |     @Composable | ||||||
|  |     actual abstract fun build() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @Composable | ||||||
|  | actual fun View.DrawVertically( | ||||||
|  |     title: String, | ||||||
|  |     block: @Composable () -> Unit | ||||||
|  | ) { | ||||||
|  |     TitleText(title) | ||||||
|  |     DefaultSmallVerticalMargin() | ||||||
|  |  | ||||||
|  |     Column(defaultModifier) { | ||||||
|  |         block() | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     DefaultSmallVerticalMargin() | ||||||
|  | } | ||||||
| @@ -0,0 +1,39 @@ | |||||||
|  | package dev.inmo.kmppscriptbuilder.core.ui | ||||||
|  |  | ||||||
|  | import androidx.compose.foundation.layout.Row | ||||||
|  | import androidx.compose.foundation.layout.padding | ||||||
|  | import androidx.compose.material.Button | ||||||
|  | import androidx.compose.material.OutlinedButton | ||||||
|  | import androidx.compose.material.Text | ||||||
|  | import androidx.compose.runtime.Composable | ||||||
|  | import androidx.compose.ui.Alignment | ||||||
|  | import androidx.compose.ui.Modifier | ||||||
|  | import androidx.compose.ui.unit.dp | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.models.GpgSigning | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.CommonTextField | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.Drawer | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.SwitchWithLabel | ||||||
|  |  | ||||||
|  | actual class GpgSigningOptionDrawer( | ||||||
|  |     private val mavenInfoView: MavenInfoView | ||||||
|  | ) : Drawer<GpgSigning> { | ||||||
|  |     @Composable | ||||||
|  |     override fun GpgSigning.draw() { | ||||||
|  |         if (mavenInfoView.gpgSignProperty == this) { | ||||||
|  |             Button({}, Modifier.padding(8.dp, 0.dp)) { | ||||||
|  |                 Text(name) | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             OutlinedButton( | ||||||
|  |                 { | ||||||
|  |                     mavenInfoView.gpgSignProperty = this | ||||||
|  |                 }, | ||||||
|  |                 Modifier.padding(8.dp, 0.dp) | ||||||
|  |             ) { | ||||||
|  |                 Text(name) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | actual fun GpgSigningOptionDrawerWithView(view: MavenInfoView): GpgSigningOptionDrawer = GpgSigningOptionDrawer(mavenInfoView = view) | ||||||
| @@ -0,0 +1,31 @@ | |||||||
|  | package dev.inmo.kmppscriptbuilder.core.ui | ||||||
|  |  | ||||||
|  | import androidx.compose.foundation.layout.Column | ||||||
|  | import androidx.compose.foundation.layout.padding | ||||||
|  | import androidx.compose.material.Button | ||||||
|  | import androidx.compose.material.Divider | ||||||
|  | import androidx.compose.runtime.Composable | ||||||
|  | import androidx.compose.ui.Modifier | ||||||
|  | import androidx.compose.ui.unit.dp | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.CommonText | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.CommonTextField | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.Drawer | ||||||
|  |  | ||||||
|  | actual object LicensesDrawer : Drawer<LicensesView> { | ||||||
|  |     @Composable | ||||||
|  |     override fun LicensesView.draw() { | ||||||
|  |         if (searchFieldFocused.value) { | ||||||
|  |             Column { | ||||||
|  |                 licensesOffersToShow.value.forEach { | ||||||
|  |                     Column(Modifier.padding(16.dp, 8.dp, 8.dp, 8.dp)) { | ||||||
|  |                         CommonText(it.title) { | ||||||
|  |                             itemsList.add(it.toLicenseState()) | ||||||
|  |                             licenseSearchFilter = "" | ||||||
|  |                         } | ||||||
|  |                         Divider() | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,33 @@ | |||||||
|  | package dev.inmo.kmppscriptbuilder.core.ui | ||||||
|  |  | ||||||
|  | import androidx.compose.foundation.layout.padding | ||||||
|  | import androidx.compose.material.Button | ||||||
|  | import androidx.compose.material.OutlinedButton | ||||||
|  | import androidx.compose.runtime.Composable | ||||||
|  | import androidx.compose.ui.Modifier | ||||||
|  | import androidx.compose.ui.unit.dp | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.CommonText | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.DefaultContentColumn | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.Drawer | ||||||
|  |  | ||||||
|  | actual class ListViewDrawer<T> : Drawer<ListView<T>> { | ||||||
|  |     @Composable | ||||||
|  |     override fun ListView<T>.draw() { | ||||||
|  |         itemsList.forEach { item -> | ||||||
|  |             DefaultContentColumn { | ||||||
|  |                 buildView(item) | ||||||
|  |                 OutlinedButton({ itemsList.remove(item) }, Modifier.padding(8.dp)) { | ||||||
|  |                     CommonText(removeItemText,) | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             Button({ itemsList.add(createItem()) }) { | ||||||
|  |                 CommonText(addItemText,) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         if (itemsList.isEmpty()) { | ||||||
|  |             Button({ itemsList.add(createItem()) }) { | ||||||
|  |                 CommonText(addItemText,) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,40 @@ | |||||||
|  | package dev.inmo.kmppscriptbuilder.core.ui | ||||||
|  |  | ||||||
|  | import androidx.compose.foundation.layout.Row | ||||||
|  | import androidx.compose.foundation.layout.padding | ||||||
|  | import androidx.compose.material.Button | ||||||
|  | import androidx.compose.material.OutlinedButton | ||||||
|  | import androidx.compose.material.Text | ||||||
|  | import androidx.compose.runtime.Composable | ||||||
|  | import androidx.compose.ui.Alignment | ||||||
|  | import androidx.compose.ui.Modifier | ||||||
|  | import androidx.compose.ui.unit.dp | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.models.JSProjectType | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.models.JVMProjectType | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.models.MultiplatformProjectType | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.models.ProjectType | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.Drawer | ||||||
|  |  | ||||||
|  | actual class ProjectTypeDrawer( | ||||||
|  |     private val projectTypeView: ProjectTypeView | ||||||
|  | ) : Drawer<ProjectType> { | ||||||
|  |     @Composable | ||||||
|  |     override fun ProjectType.draw() { | ||||||
|  |         if (projectTypeView.projectType == this) { | ||||||
|  |             Button({}, Modifier.padding(8.dp, 0.dp)) { | ||||||
|  |                 Text(name) | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             OutlinedButton( | ||||||
|  |                 { | ||||||
|  |                     projectTypeView.projectType = this | ||||||
|  |                 }, | ||||||
|  |                 Modifier.padding(8.dp, 0.dp) | ||||||
|  |             ) { | ||||||
|  |                 Text(name) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | actual fun ProjectTypeDrawerWithView(view: ProjectTypeView): ProjectTypeDrawer = ProjectTypeDrawer(projectTypeView = view) | ||||||
| @@ -0,0 +1,40 @@ | |||||||
|  | package dev.inmo.kmppscriptbuilder.core.ui | ||||||
|  |  | ||||||
|  | import androidx.compose.foundation.layout.padding | ||||||
|  | import androidx.compose.material.Button | ||||||
|  | import androidx.compose.material.OutlinedButton | ||||||
|  | import androidx.compose.material.Text | ||||||
|  | import androidx.compose.runtime.Composable | ||||||
|  | import androidx.compose.ui.Modifier | ||||||
|  | import androidx.compose.ui.unit.dp | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.models.MavenPublishingRepository | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.ui.utils.Drawer | ||||||
|  |  | ||||||
|  | actual class RepositoryCredentialTypeDrawer( | ||||||
|  |     private val state: RepositoryState | ||||||
|  | ) : Drawer<MavenPublishingRepository.CredentialsType> { | ||||||
|  |     @Composable | ||||||
|  |     override fun MavenPublishingRepository.CredentialsType.draw() { | ||||||
|  |         val name = when (this@draw) { | ||||||
|  |             is MavenPublishingRepository.CredentialsType.HttpHeaderCredentials -> "Headers" | ||||||
|  |             MavenPublishingRepository.CredentialsType.Nothing -> "No" | ||||||
|  |             is MavenPublishingRepository.CredentialsType.UsernameAndPassword -> "Username and password" | ||||||
|  |         } | ||||||
|  |         if (state.credsType == this) { | ||||||
|  |             Button({}, Modifier.padding(8.dp, 0.dp)) { | ||||||
|  |                 Text(name) | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             OutlinedButton( | ||||||
|  |                 { | ||||||
|  |                     state.credsType = this | ||||||
|  |                 }, | ||||||
|  |                 Modifier.padding(8.dp, 0.dp) | ||||||
|  |             ) { | ||||||
|  |                 Text(name) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | actual fun RepositoryCredentialTypeDrawerWithState(repositoryState: RepositoryState): RepositoryCredentialTypeDrawer = RepositoryCredentialTypeDrawer(repositoryState) | ||||||
| @@ -0,0 +1,88 @@ | |||||||
|  | package dev.inmo.kmppscriptbuilder.core.ui | ||||||
|  |  | ||||||
|  | import androidx.compose.foundation.ExperimentalFoundationApi | ||||||
|  | import androidx.compose.foundation.Image | ||||||
|  | import androidx.compose.foundation.TooltipArea | ||||||
|  | import androidx.compose.foundation.clickable | ||||||
|  | import androidx.compose.foundation.layout.padding | ||||||
|  | import androidx.compose.foundation.shape.RoundedCornerShape | ||||||
|  | import androidx.compose.material.IconButton | ||||||
|  | import androidx.compose.material.MaterialTheme | ||||||
|  | import androidx.compose.material.Surface | ||||||
|  | import androidx.compose.material.Text | ||||||
|  | import androidx.compose.material.TopAppBar | ||||||
|  | import androidx.compose.material.primarySurface | ||||||
|  | import androidx.compose.runtime.Composable | ||||||
|  | import androidx.compose.ui.Modifier | ||||||
|  | import androidx.compose.ui.draw.shadow | ||||||
|  | import androidx.compose.ui.res.painterResource | ||||||
|  | import androidx.compose.ui.unit.dp | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.models.Config | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.utils.exportGradle | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.utils.openNewConfig | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.utils.saveAs | ||||||
|  | import dev.inmo.kmppscriptbuilder.core.utils.saveConfig | ||||||
|  |  | ||||||
|  | @OptIn(ExperimentalFoundationApi::class) | ||||||
|  | @Composable | ||||||
|  | private fun createIcon( | ||||||
|  |     tooltip: String, | ||||||
|  |     resource: String, | ||||||
|  |     onClick: () -> Unit | ||||||
|  | ) { | ||||||
|  |     TooltipArea( | ||||||
|  |         tooltip = { | ||||||
|  |             Surface( | ||||||
|  |                 modifier = Modifier.shadow(4.dp), | ||||||
|  |                 color = MaterialTheme.colors.primarySurface, | ||||||
|  |                 shape = RoundedCornerShape(4.dp) | ||||||
|  |             ) { | ||||||
|  |                 Text(tooltip, modifier = Modifier.padding(10.dp), color = MaterialTheme.colors.onPrimary) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     ) { | ||||||
|  |         IconButton(onClick) { | ||||||
|  |             Image( | ||||||
|  |                 painter = painterResource(resource), | ||||||
|  |                 contentDescription = tooltip | ||||||
|  |             ) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @Composable | ||||||
|  | actual fun TopAppBar( | ||||||
|  |     config: Config, | ||||||
|  |     saveAvailable: Boolean, | ||||||
|  |     onSaveAvailable: (Boolean) -> Unit, | ||||||
|  |     onNewConfig: (Config) -> Unit | ||||||
|  | ) { | ||||||
|  |     TopAppBar( | ||||||
|  |         @Composable { | ||||||
|  |             Text("Kotlin publication scripts builder", Modifier.clickable { println(config) }) | ||||||
|  |         }, | ||||||
|  |         actions = { | ||||||
|  |             createIcon("Open file", "images/open_file.svg") { | ||||||
|  |                 openNewConfig(onNewConfig) | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (saveAvailable) { | ||||||
|  |                 createIcon("Save", "images/save_file.svg") { | ||||||
|  |                     saveConfig(config) | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (saveAvailable) { | ||||||
|  |                 createIcon("Export Gradle script", "images/export_gradle.svg") { | ||||||
|  |                     exportGradle(config) | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             createIcon("Save as", "images/save_as.svg") { | ||||||
|  |                 if (saveAs(config)) { | ||||||
|  |                     onSaveAvailable(true) | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     ) | ||||||
|  | } | ||||||
| @@ -0,0 +1,113 @@ | |||||||
|  | package dev.inmo.kmppscriptbuilder.core.ui.utils | ||||||
|  |  | ||||||
|  | import androidx.compose.foundation.clickable | ||||||
|  | import androidx.compose.foundation.layout.Arrangement | ||||||
|  | import androidx.compose.foundation.layout.Box | ||||||
|  | import androidx.compose.foundation.layout.Column | ||||||
|  | import androidx.compose.foundation.layout.Row | ||||||
|  | import androidx.compose.foundation.layout.Spacer | ||||||
|  | import androidx.compose.foundation.layout.fillMaxWidth | ||||||
|  | import androidx.compose.foundation.layout.padding | ||||||
|  | import androidx.compose.material.Divider | ||||||
|  | import androidx.compose.material.OutlinedTextField | ||||||
|  | import androidx.compose.material.Switch | ||||||
|  | import androidx.compose.material.Text | ||||||
|  | import androidx.compose.runtime.Composable | ||||||
|  | import androidx.compose.ui.Alignment | ||||||
|  | import androidx.compose.ui.Modifier | ||||||
|  | import androidx.compose.ui.focus.onFocusChanged | ||||||
|  | import androidx.compose.ui.text.TextStyle | ||||||
|  | import androidx.compose.ui.unit.dp | ||||||
|  | import androidx.compose.ui.unit.sp | ||||||
|  |  | ||||||
|  |  | ||||||
|  | val commonTextFieldTextStyle = TextStyle( | ||||||
|  |     fontSize = 12.sp | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | @Composable | ||||||
|  | actual fun SwitchWithLabel( | ||||||
|  |     label: String, | ||||||
|  |     checked: Boolean, | ||||||
|  |     placeSwitchAtTheStart: Boolean, | ||||||
|  |     switchEnabled: Boolean, | ||||||
|  |     onCheckedChange: (Boolean) -> Unit | ||||||
|  | ) { | ||||||
|  |     Row(Modifier.padding(0.dp, 8.dp).clickable { onCheckedChange(!checked) }, Arrangement.Start, Alignment.Top) { | ||||||
|  |         val switchCreator = @Composable { | ||||||
|  |             Switch(checked, null, Modifier.padding(8.dp, 0.dp), enabled = switchEnabled) | ||||||
|  |         } | ||||||
|  |         if (placeSwitchAtTheStart) { | ||||||
|  |             switchCreator() | ||||||
|  |         } | ||||||
|  |         Box(Modifier.fillMaxWidth().align(Alignment.CenterVertically)) { | ||||||
|  |             CommonText(label) | ||||||
|  |         } | ||||||
|  |         if (!placeSwitchAtTheStart) { | ||||||
|  |             switchCreator() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @Composable | ||||||
|  | actual fun CommonTextField( | ||||||
|  |     presetText: String, | ||||||
|  |     hint: String?, | ||||||
|  |     onFocusChanged: (Boolean) -> Unit, | ||||||
|  |     onChange: (String) -> Unit | ||||||
|  | ) { | ||||||
|  |     OutlinedTextField( | ||||||
|  |         presetText, | ||||||
|  |         onChange, | ||||||
|  |         Modifier.fillMaxWidth().onFocusChanged { | ||||||
|  |             onFocusChanged(it.isFocused) | ||||||
|  |         }, | ||||||
|  |         singleLine = true, | ||||||
|  |         label = hint ?.let { | ||||||
|  |             { | ||||||
|  |                 CommonText(hint) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     ) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @Composable | ||||||
|  | actual fun CommonText(text: String, onClick: (() -> Unit)?) { | ||||||
|  |     Text(text, modifier = Modifier.run { onClick ?.let { clickable(onClick = it) } ?: this }) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @Composable | ||||||
|  | actual fun TitleText(text: String) { | ||||||
|  |     Text( | ||||||
|  |         text, Modifier.padding(0.dp, 8.dp), fontSize = 18.sp | ||||||
|  |     ) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @Composable | ||||||
|  | actual fun <T> ButtonsPanel( | ||||||
|  |     title: String, | ||||||
|  |     data: Iterable<T>, | ||||||
|  |     itemDrawer: @Composable (T) -> Unit | ||||||
|  | ) { | ||||||
|  |     Row { | ||||||
|  |         Text(title, Modifier.padding(8.dp)) | ||||||
|  |         data.forEach { itemDrawer(it) } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @Composable | ||||||
|  | actual fun DefaultDivider() { | ||||||
|  |     Divider() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @Composable | ||||||
|  | actual fun DefaultSmallVerticalMargin() { | ||||||
|  |     Spacer(Modifier.padding(0.dp, 4.dp)) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @Composable | ||||||
|  | actual fun DefaultContentColumn(block: @Composable () -> Unit) { | ||||||
|  |     Column(Modifier.padding(8.dp)) { | ||||||
|  |         block() | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -1,4 +1,4 @@ | |||||||
| package dev.inmo.kmppscriptbuilder.desktop.utils | package dev.inmo.kmppscriptbuilder.core.ui.utils | ||||||
| 
 | 
 | ||||||
| import java.io.File | import java.io.File | ||||||
| import javax.swing.filechooser.FileFilter | import javax.swing.filechooser.FileFilter | ||||||
| @@ -1,40 +1,40 @@ | |||||||
| package dev.inmo.kmppscriptbuilder.desktop.utils | package dev.inmo.kmppscriptbuilder.core.utils | ||||||
| 
 | 
 | ||||||
| import dev.inmo.kmppscriptbuilder.core.models.Config | import dev.inmo.kmppscriptbuilder.core.models.Config | ||||||
| import dev.inmo.kmppscriptbuilder.core.utils.serialFormat | import dev.inmo.kmppscriptbuilder.core.ui.utils.FileFilter | ||||||
|  | import dev.inmo.micro_utils.common.MPPFile | ||||||
| import java.io.File | import java.io.File | ||||||
| import javax.swing.JFileChooser | import javax.swing.JFileChooser | ||||||
| 
 | 
 | ||||||
| private const val appExtension = "kpsb" | fun MPPFile.text() = readText() | ||||||
| 
 | 
 | ||||||
| private var lastFile: File? = null | internal var lastFile: MPPFile? = null | ||||||
| 
 | 
 | ||||||
| fun loadConfigFile(file: File): Config { | fun loadConfigFile(file: MPPFile): Config { | ||||||
|     lastFile = file |     lastFile = file | ||||||
|     return serialFormat.decodeFromString(Config.serializer(), file.readText()) |     return serialFormat.decodeFromString(Config.serializer(), file.text()) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fun loadConfig(): Config? { | actual fun openNewConfig(onParsed: (Config) -> Unit) { | ||||||
|     val fc = JFileChooser(lastFile ?.parent) |     val fc = JFileChooser(lastFile ?.parent) | ||||||
|     fc.addChoosableFileFilter(FileFilter("Kotlin Publication Scripts Builder", Regex(".*\\.$appExtension"))) |     fc.addChoosableFileFilter(FileFilter("Kotlin Publication Scripts Builder", Regex(".*\\.$appExtension"))) | ||||||
|     fc.addChoosableFileFilter(FileFilter("JSON", Regex(".*\\.json"))) |     fc.addChoosableFileFilter(FileFilter("JSON", Regex(".*\\.json"))) | ||||||
|     return when (fc.showOpenDialog(null)) { |     when (fc.showOpenDialog(null)) { | ||||||
|         JFileChooser.APPROVE_OPTION -> { |         JFileChooser.APPROVE_OPTION -> { | ||||||
|             val file = fc.selectedFile |             val file = fc.selectedFile | ||||||
|             lastFile = file |             lastFile = file | ||||||
|             return serialFormat.decodeFromString(Config.serializer(), fc.selectedFile.readText()) |             onParsed(serialFormat.decodeFromString(Config.serializer(), fc.selectedFile.readText())) | ||||||
|         } |         } | ||||||
|         else -> null |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fun saveConfig(config: Config): Boolean { | actual fun saveConfig(config: Config): Boolean { | ||||||
|     return lastFile ?.also { |     return lastFile ?.also { | ||||||
|         it.writeText(serialFormat.encodeToString(Config.serializer(), config)) |         it.writeText(serialFormat.encodeToString(Config.serializer(), config)) | ||||||
|     } != null |     } != null | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fun exportGradle(config: Config): Boolean { | actual fun exportGradle(config: Config): Boolean { | ||||||
|     val fc = JFileChooser(lastFile ?.parent) |     val fc = JFileChooser(lastFile ?.parent) | ||||||
|     fc.fileSelectionMode = JFileChooser.DIRECTORIES_ONLY |     fc.fileSelectionMode = JFileChooser.DIRECTORIES_ONLY | ||||||
|     return when (fc.showSaveDialog(null)) { |     return when (fc.showSaveDialog(null)) { | ||||||
| @@ -55,7 +55,7 @@ fun exportGradle(config: Config): Boolean { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fun saveAs(config: Config): Boolean { | actual fun saveAs(config: Config): Boolean { | ||||||
|     val fc = JFileChooser(lastFile ?.parent) |     val fc = JFileChooser(lastFile ?.parent) | ||||||
|     fc.addChoosableFileFilter(FileFilter("Kotlin Publication Scripts Builder", Regex(".*\\.$appExtension"))) |     fc.addChoosableFileFilter(FileFilter("Kotlin Publication Scripts Builder", Regex(".*\\.$appExtension"))) | ||||||
|     fc.addChoosableFileFilter(FileFilter("JSON", Regex(".*\\.json"))) |     fc.addChoosableFileFilter(FileFilter("JSON", Regex(".*\\.json"))) | ||||||
| @@ -1,10 +1,9 @@ | |||||||
| package dev.inmo.kmppscriptbuilder.desktop.utils | package dev.inmo.kmppscriptbuilder.core.utils | ||||||
| 
 | 
 | ||||||
| import java.awt.Desktop | import java.awt.Desktop | ||||||
| import java.lang.Exception |  | ||||||
| import java.net.URI | import java.net.URI | ||||||
| 
 | 
 | ||||||
| fun openLink(link: String): Boolean { | actual fun openLink(link: String): Boolean { | ||||||
|     val desktop = if (Desktop.isDesktopSupported()) Desktop.getDesktop() else null |     val desktop = if (Desktop.isDesktopSupported()) Desktop.getDesktop() else null | ||||||
|     if (desktop != null && desktop.isSupported(Desktop.Action.BROWSE)) { |     if (desktop != null && desktop.isSupported(Desktop.Action.BROWSE)) { | ||||||
|         try { |         try { | ||||||
| @@ -0,0 +1,2 @@ | |||||||
|  | package dev.inmo.kmppscriptbuilder.core.utils  | ||||||
|  |  | ||||||
| @@ -1 +0,0 @@ | |||||||
| <manifest package="dev.inmo.KotlinPublicationScriptsBuilder.core"/> |  | ||||||
| @@ -1,40 +0,0 @@ | |||||||
| apply plugin: 'com.getkeepsafe.dexcount' |  | ||||||
|  |  | ||||||
| android { |  | ||||||
|     compileSdkVersion "$android_compileSdkVersion".toInteger() |  | ||||||
|     buildToolsVersion "$android_buildToolsVersion" |  | ||||||
|  |  | ||||||
|     defaultConfig { |  | ||||||
|         minSdkVersion "$android_minSdkVersion".toInteger() |  | ||||||
|         targetSdkVersion "$android_compileSdkVersion".toInteger() |  | ||||||
|         versionCode "${android_code_version}".toInteger() |  | ||||||
|         versionName "$version" |  | ||||||
|     } |  | ||||||
|     buildTypes { |  | ||||||
|         release { |  | ||||||
|             minifyEnabled false |  | ||||||
|         } |  | ||||||
|         debug { |  | ||||||
|             debuggable true |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     packagingOptions { |  | ||||||
|         exclude 'META-INF/kotlinx-serialization-runtime.kotlin_module' |  | ||||||
|         exclude 'META-INF/kotlinx-serialization-cbor.kotlin_module' |  | ||||||
|         exclude 'META-INF/kotlinx-serialization-properties.kotlin_module' |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     compileOptions { |  | ||||||
|         sourceCompatibility JavaVersion.VERSION_1_8 |  | ||||||
|         targetCompatibility JavaVersion.VERSION_1_8 |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     kotlinOptions { |  | ||||||
|         jvmTarget = JavaVersion.VERSION_1_8.toString() |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     sourceSets { |  | ||||||
|         main.java.srcDirs += 'src/main/kotlin' |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,37 +0,0 @@ | |||||||
| plugins { |  | ||||||
|     id "org.jetbrains.kotlin.multiplatform" |  | ||||||
|     id "org.jetbrains.kotlin.plugin.serialization" |  | ||||||
|     id("org.jetbrains.compose") version "$compose_version" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| apply from: "$mppJavaProjectPresetPath" |  | ||||||
|  |  | ||||||
| kotlin { |  | ||||||
|     jvm { |  | ||||||
|         compilations.main.kotlinOptions { |  | ||||||
|             jvmTarget = "11" |  | ||||||
|             useIR = true |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     sourceSets { |  | ||||||
|         commonMain { |  | ||||||
|             dependencies { |  | ||||||
|                 implementation project(":kmppscriptbuilder.core") |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         jvmMain { |  | ||||||
|             dependencies { |  | ||||||
|                 implementation(compose.desktop.currentOs) |  | ||||||
|                 api "io.ktor:ktor-client-cio:$ktor_version" |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| compose.desktop { |  | ||||||
|     application { |  | ||||||
|         mainClass = "dev.inmo.kmppscriptbuilder.desktop.BuilderKt" |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| @@ -1,62 +0,0 @@ | |||||||
| package dev.inmo.kmppscriptbuilder.desktop |  | ||||||
|  |  | ||||||
| import androidx.compose.desktop.Window |  | ||||||
| import androidx.compose.foundation.* |  | ||||||
| import androidx.compose.foundation.layout.* |  | ||||||
| import androidx.compose.material.* |  | ||||||
| import androidx.compose.ui.Alignment |  | ||||||
| import androidx.compose.ui.Modifier |  | ||||||
| import androidx.compose.ui.graphics.Color |  | ||||||
| import dev.inmo.kmppscriptbuilder.desktop.utils.* |  | ||||||
| import dev.inmo.kmppscriptbuilder.desktop.views.* |  | ||||||
| import java.io.File |  | ||||||
|  |  | ||||||
| //private val uncaughtExceptionsBC = BroadcastChannel<DefaultErrorHandler.ErrorEvent>(Channel.CONFLATED) |  | ||||||
| //val uncaughtExceptionsFlow: Flow<DefaultErrorHandler.ErrorEvent> = uncaughtExceptionsBC.asFlow() |  | ||||||
|  |  | ||||||
| fun main(args: Array<String>) = Window(title = "Kotlin Multiplatform Publishing Builder") { |  | ||||||
|     val builder = BuilderView() |  | ||||||
|     MaterialTheme( |  | ||||||
|         Colors( |  | ||||||
|             primary = Color(0x01, 0x57, 0x9b), |  | ||||||
|             primaryVariant = Color(0x00, 0x2f, 0x6c), |  | ||||||
|             secondary = Color(0xb2, 0xeb, 0xf2), |  | ||||||
|             secondaryVariant = Color(0x81, 0xb9, 0xbf), |  | ||||||
|             background = Color(0xe1, 0xe2, 0xe1), |  | ||||||
|             surface = Color(0xf5, 0xf5, 0xf6), |  | ||||||
|             error = Color(0xb7, 0x1c, 0x1c), |  | ||||||
|             onPrimary = Color.White, |  | ||||||
|             onSecondary = Color.Black, |  | ||||||
|             onBackground = Color.Black, |  | ||||||
|             onSurface = Color.Black, |  | ||||||
|             onError = Color.White, |  | ||||||
|             isLight = MaterialTheme.colors.isLight, |  | ||||||
|         ) |  | ||||||
|     ) { |  | ||||||
|         Box( |  | ||||||
|             Modifier.fillMaxSize() |  | ||||||
|                 .background(color = Color(245, 245, 245)) |  | ||||||
|         ) { |  | ||||||
|  |  | ||||||
|             val stateVertical = rememberScrollState(0) |  | ||||||
|             Box( |  | ||||||
|                 modifier = Modifier |  | ||||||
|                     .fillMaxSize() |  | ||||||
|                     .verticalScroll(stateVertical) |  | ||||||
|             ) { |  | ||||||
|                 builder.init() |  | ||||||
|  |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             VerticalScrollbar( |  | ||||||
|                 modifier = Modifier.align(Alignment.CenterEnd).fillMaxHeight(), |  | ||||||
|                 adapter = rememberScrollbarAdapter(stateVertical) |  | ||||||
|             ) |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if (args.isNotEmpty()) { |  | ||||||
|         val config = loadConfigFile(File(args.first())) |  | ||||||
|         builder.config = config |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,60 +0,0 @@ | |||||||
| package dev.inmo.kmppscriptbuilder.desktop.utils |  | ||||||
|  |  | ||||||
| import androidx.compose.foundation.clickable |  | ||||||
| import androidx.compose.foundation.layout.* |  | ||||||
| import androidx.compose.material.* |  | ||||||
| import androidx.compose.runtime.Composable |  | ||||||
| import androidx.compose.ui.Alignment |  | ||||||
| import androidx.compose.ui.Modifier |  | ||||||
| import androidx.compose.ui.text.TextStyle |  | ||||||
| import androidx.compose.ui.unit.dp |  | ||||||
| import androidx.compose.ui.unit.sp |  | ||||||
|  |  | ||||||
| val commonTextFieldTextStyle = TextStyle( |  | ||||||
|     fontSize = 12.sp |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| @Composable |  | ||||||
| inline fun TitleText(text: String) = Text( |  | ||||||
|     text, Modifier.padding(0.dp, 8.dp), fontSize = 18.sp |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| @Composable |  | ||||||
| inline fun CommonText(text: String, modifier: Modifier = Modifier) = Text( |  | ||||||
|     text, modifier = modifier |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| @Composable |  | ||||||
| inline fun CommonTextField(presetText: String, hint: String, noinline onChange: (String) -> Unit) = OutlinedTextField( |  | ||||||
|     presetText, |  | ||||||
|     onChange, |  | ||||||
|     Modifier.fillMaxWidth(), |  | ||||||
|     singleLine = true, |  | ||||||
|     label = { |  | ||||||
|         CommonText(hint) |  | ||||||
|     } |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| @Composable |  | ||||||
| inline fun SwitchWithLabel( |  | ||||||
|     label: String, |  | ||||||
|     checked: Boolean, |  | ||||||
|     placeSwitchAtTheStart: Boolean = false, |  | ||||||
|     switchEnabled: Boolean = true, |  | ||||||
|     modifier: Modifier = Modifier.padding(0.dp, 8.dp), |  | ||||||
|     horizontalArrangement: Arrangement.Horizontal = Arrangement.Start, |  | ||||||
|     verticalAlignment: Alignment.Vertical = Alignment.Top, |  | ||||||
|     switchModifier: Modifier = Modifier.padding(8.dp, 0.dp), |  | ||||||
|     noinline onCheckedChange: (Boolean) -> Unit |  | ||||||
| ) = Row(modifier, horizontalArrangement, verticalAlignment) { |  | ||||||
|     val switchCreator = @Composable { |  | ||||||
|         Switch(checked, onCheckedChange, switchModifier, enabled = switchEnabled) |  | ||||||
|     } |  | ||||||
|     if (placeSwitchAtTheStart) { |  | ||||||
|         switchCreator() |  | ||||||
|     } |  | ||||||
|     CommonText(label, Modifier.align(Alignment.CenterVertically).clickable {  }) |  | ||||||
|     if (!placeSwitchAtTheStart) { |  | ||||||
|         switchCreator() |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,34 +0,0 @@ | |||||||
| package dev.inmo.kmppscriptbuilder.desktop.utils |  | ||||||
|  |  | ||||||
| import androidx.compose.foundation.layout.* |  | ||||||
| import androidx.compose.runtime.Composable |  | ||||||
| import androidx.compose.ui.Modifier |  | ||||||
| import androidx.compose.ui.unit.dp |  | ||||||
|  |  | ||||||
| abstract class View { |  | ||||||
|     protected open val defaultModifier = Modifier.fillMaxWidth().padding(8.dp) |  | ||||||
|  |  | ||||||
|     @Composable |  | ||||||
|     abstract fun build() |  | ||||||
| } |  | ||||||
|  |  | ||||||
| abstract class VerticalView(val title: String) : View() { |  | ||||||
|     abstract val content: @Composable ColumnScope.() -> Unit |  | ||||||
|     @Composable |  | ||||||
|     override fun build() { |  | ||||||
|         TitleText(title) |  | ||||||
|  |  | ||||||
|         Column( |  | ||||||
|             defaultModifier |  | ||||||
|         ) { |  | ||||||
|             content() |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         Spacer(Modifier.fillMaxWidth().height(8.dp)) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| @Composable |  | ||||||
| fun <T : View> T.init(): T = apply { |  | ||||||
|     build() |  | ||||||
| } |  | ||||||
| @@ -1,111 +0,0 @@ | |||||||
| package dev.inmo.kmppscriptbuilder.desktop.views |  | ||||||
|  |  | ||||||
| import androidx.compose.foundation.Image |  | ||||||
| import androidx.compose.foundation.clickable |  | ||||||
| import androidx.compose.foundation.layout.* |  | ||||||
| import androidx.compose.material.* |  | ||||||
| import androidx.compose.runtime.* |  | ||||||
| import androidx.compose.ui.Modifier |  | ||||||
| import androidx.compose.ui.graphics.asImageBitmap |  | ||||||
| import androidx.compose.ui.platform.DesktopPlatform |  | ||||||
| import androidx.compose.ui.res.loadSvgResource |  | ||||||
| import androidx.compose.ui.res.svgResource |  | ||||||
| import androidx.compose.ui.unit.Density |  | ||||||
| import androidx.compose.ui.unit.dp |  | ||||||
| import dev.inmo.kmppscriptbuilder.core.models.Config |  | ||||||
| import dev.inmo.kmppscriptbuilder.desktop.utils.* |  | ||||||
| import dev.inmo.micro_utils.coroutines.safelyWithoutExceptions |  | ||||||
| import java.awt.Desktop |  | ||||||
| import java.lang.Exception |  | ||||||
| import java.net.URL |  | ||||||
|  |  | ||||||
| class BuilderView : View() { |  | ||||||
|     private val projectTypeView = ProjectTypeView() |  | ||||||
|     private val mavenInfoView = MavenInfoView() |  | ||||||
|     private val licensesView = LicensesView() |  | ||||||
|     private var saveAvailableState by mutableStateOf(false) |  | ||||||
|  |  | ||||||
|     override val defaultModifier: Modifier = Modifier.fillMaxSize() |  | ||||||
|  |  | ||||||
|     var config: Config |  | ||||||
|         get() = Config(licensesView.licenses, mavenInfoView.mavenConfig, projectTypeView.projectType) |  | ||||||
|         set(value) { |  | ||||||
|             licensesView.licenses = value.licenses |  | ||||||
|             mavenInfoView.mavenConfig = value.mavenConfig |  | ||||||
|             projectTypeView.projectType = value.type |  | ||||||
|             saveAvailableState = true |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     @Composable |  | ||||||
|     override fun build() { |  | ||||||
|         Box(Modifier.fillMaxSize()) { |  | ||||||
|             Column() { |  | ||||||
|                 TopAppBar( |  | ||||||
|                     @Composable { |  | ||||||
|                         CommonText("Kotlin publication scripts builder", Modifier.clickable { println(config) }) |  | ||||||
|                     }, |  | ||||||
|                     actions = { |  | ||||||
|                         IconButton( |  | ||||||
|                             { |  | ||||||
|                                 loadConfig()?.also { |  | ||||||
|                                     config = it |  | ||||||
|                                 } |  | ||||||
|                             } |  | ||||||
|                         ) { |  | ||||||
|                             Image( |  | ||||||
|                                 painter = svgResource("images/open_file.svg"), |  | ||||||
|                                 contentDescription = "Open file" |  | ||||||
|                             ) |  | ||||||
|                         } |  | ||||||
|  |  | ||||||
|                         if (saveAvailableState) { |  | ||||||
|                             IconButton( |  | ||||||
|                                 { |  | ||||||
|                                     saveConfig(config) |  | ||||||
|                                 } |  | ||||||
|                             ) { |  | ||||||
|                                 Image( |  | ||||||
|                                     painter = svgResource("images/save_file.svg"), |  | ||||||
|                                     contentDescription = "Save file" |  | ||||||
|                                 ) |  | ||||||
|                             } |  | ||||||
|                         } |  | ||||||
|  |  | ||||||
|                         if (saveAvailableState) { |  | ||||||
|                             IconButton( |  | ||||||
|                                 { |  | ||||||
|                                     exportGradle(config) |  | ||||||
|                                 } |  | ||||||
|                             ) { |  | ||||||
|                                 Image( |  | ||||||
|                                     painter = svgResource("images/export_gradle.svg"), |  | ||||||
|                                     contentDescription = "Export Gradle script" |  | ||||||
|                                 ) |  | ||||||
|                             } |  | ||||||
|                         } |  | ||||||
|  |  | ||||||
|                         IconButton( |  | ||||||
|                             { |  | ||||||
|                                 if (saveAs(config)) { |  | ||||||
|                                     saveAvailableState = true |  | ||||||
|                                 } |  | ||||||
|                             } |  | ||||||
|                         ) { |  | ||||||
|                             Image( |  | ||||||
|                                 painter = svgResource("images/save_as.svg"), |  | ||||||
|                                 contentDescription = "Export Gradle script" |  | ||||||
|                             ) |  | ||||||
|                         } |  | ||||||
|                     } |  | ||||||
|                 ) |  | ||||||
|                 Column(Modifier.padding(8.dp)) { |  | ||||||
|                     projectTypeView.init() |  | ||||||
|                     Divider() |  | ||||||
|                     licensesView.init() |  | ||||||
|                     Divider() |  | ||||||
|                     mavenInfoView.init() |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,95 +0,0 @@ | |||||||
| package dev.inmo.kmppscriptbuilder.desktop.views |  | ||||||
|  |  | ||||||
| import androidx.compose.foundation.clickable |  | ||||||
| import androidx.compose.foundation.layout.* |  | ||||||
| import androidx.compose.material.Button |  | ||||||
| import androidx.compose.material.Divider |  | ||||||
| import androidx.compose.runtime.* |  | ||||||
| import androidx.compose.ui.Modifier |  | ||||||
| import androidx.compose.ui.unit.dp |  | ||||||
| import dev.inmo.kmppscriptbuilder.core.models.License |  | ||||||
| import dev.inmo.kmppscriptbuilder.core.models.getLicenses |  | ||||||
| import dev.inmo.kmppscriptbuilder.desktop.utils.* |  | ||||||
| import io.ktor.client.HttpClient |  | ||||||
| import kotlinx.coroutines.* |  | ||||||
|  |  | ||||||
| private class LicenseState( |  | ||||||
|     id: String = "", |  | ||||||
|     title: String = "", |  | ||||||
|     url: String? = null |  | ||||||
| ) { |  | ||||||
|     var id: String by mutableStateOf(id) |  | ||||||
|     var title: String by mutableStateOf(title) |  | ||||||
|     var url: String? by mutableStateOf(url) |  | ||||||
|  |  | ||||||
|     fun toLicense() = License(id, title, url) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| private fun License.toLicenseState() = LicenseState(id, title, url) |  | ||||||
|  |  | ||||||
| class LicensesView: VerticalView("Licenses") { |  | ||||||
|     private var licensesListState = mutableStateListOf<LicenseState>() |  | ||||||
|     var licenses: List<License> |  | ||||||
|         get() = licensesListState.map { it.toLicense() } |  | ||||||
|         set(value) { |  | ||||||
|             licensesListState.clear() |  | ||||||
|             licensesListState.addAll(value.map { it.toLicenseState() }) |  | ||||||
|         } |  | ||||||
|     private val availableLicensesState = mutableStateListOf<License>() |  | ||||||
|     private val licensesOffersToShow = mutableStateListOf<License>() |  | ||||||
|     private var licenseSearchFilter by mutableStateOf("") |  | ||||||
|  |  | ||||||
|     init { |  | ||||||
|         CoroutineScope(Dispatchers.Default).launch { |  | ||||||
|             val client = HttpClient() |  | ||||||
|             availableLicensesState.addAll(client.getLicenses().values) |  | ||||||
|             client.close() |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     override val content: @Composable ColumnScope.() -> Unit = { |  | ||||||
|         CommonTextField(licenseSearchFilter, "Search filter") { filterText -> |  | ||||||
|             licenseSearchFilter = filterText |  | ||||||
|             licensesOffersToShow.clear() |  | ||||||
|             if (licenseSearchFilter.isNotEmpty()) { |  | ||||||
|                 licensesOffersToShow.addAll( |  | ||||||
|                     availableLicensesState.filter { filterText.all { symbol -> symbol.toLowerCase() in it.title } } |  | ||||||
|                 ) |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         Column { |  | ||||||
|             licensesOffersToShow.forEach { |  | ||||||
|                 Column(Modifier.padding(16.dp, 8.dp, 8.dp, 8.dp)) { |  | ||||||
|                     CommonText(it.title, Modifier.clickable { |  | ||||||
|                         licensesListState.add(it.toLicenseState()) |  | ||||||
|                         licenseSearchFilter = "" |  | ||||||
|                         licensesOffersToShow.clear() |  | ||||||
|                     }) |  | ||||||
|                     Divider() |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         Button({ licensesListState.add(LicenseState()) }, Modifier.padding(8.dp)) { |  | ||||||
|             CommonText("Add empty license") |  | ||||||
|         } |  | ||||||
|         licensesListState.forEach { license -> |  | ||||||
|             Column(Modifier.padding(8.dp)) { |  | ||||||
|                 CommonTextField( |  | ||||||
|                     license.id, |  | ||||||
|                     "License ID" |  | ||||||
|                 ) { license.id = it } |  | ||||||
|                 CommonTextField( |  | ||||||
|                     license.title, |  | ||||||
|                     "License title" |  | ||||||
|                 ) { license.title = it } |  | ||||||
|                 CommonTextField( |  | ||||||
|                     license.url ?: "", |  | ||||||
|                     "License URL" |  | ||||||
|                 ) { license.url = it } |  | ||||||
|                 Button({ licensesListState.remove(license) }, Modifier.padding(8.dp)) { |  | ||||||
|                     CommonText("Remove") |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,33 +0,0 @@ | |||||||
| package dev.inmo.kmppscriptbuilder.desktop.views |  | ||||||
|  |  | ||||||
| import androidx.compose.foundation.layout.* |  | ||||||
| import androidx.compose.material.* |  | ||||||
| import androidx.compose.runtime.* |  | ||||||
| import androidx.compose.ui.Modifier |  | ||||||
| import androidx.compose.ui.unit.dp |  | ||||||
| import dev.inmo.kmppscriptbuilder.desktop.utils.* |  | ||||||
|  |  | ||||||
| abstract class ListView<T>(title: String) : VerticalView(title) { |  | ||||||
|     protected val itemsList = mutableStateListOf<T>() |  | ||||||
|  |  | ||||||
|     protected open val addItemText: String = "Add" |  | ||||||
|     protected open val removeItemText: String = "Remove" |  | ||||||
|  |  | ||||||
|     protected abstract fun createItem(): T |  | ||||||
|     @Composable |  | ||||||
|     protected abstract fun buildView(item: T) |  | ||||||
|  |  | ||||||
|     override val content: @Composable ColumnScope.() -> Unit = { |  | ||||||
|         Button({ itemsList.add(createItem()) }) { |  | ||||||
|             CommonText(addItemText) |  | ||||||
|         } |  | ||||||
|         itemsList.forEach { item -> |  | ||||||
|             Column(Modifier.padding(8.dp)) { |  | ||||||
|                 buildView(item) |  | ||||||
|                 Button({ itemsList.remove(item) }, Modifier.padding(8.dp)) { |  | ||||||
|                     CommonText(removeItemText) |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,77 +0,0 @@ | |||||||
| package dev.inmo.kmppscriptbuilder.desktop.views |  | ||||||
|  |  | ||||||
| import androidx.compose.foundation.layout.ColumnScope |  | ||||||
| import androidx.compose.runtime.* |  | ||||||
| import dev.inmo.kmppscriptbuilder.core.models.MavenConfig |  | ||||||
| import dev.inmo.kmppscriptbuilder.core.models.SonatypeRepository |  | ||||||
| import dev.inmo.kmppscriptbuilder.desktop.utils.* |  | ||||||
|  |  | ||||||
| class MavenInfoView : VerticalView("Project information") { |  | ||||||
|     private var projectNameProperty by mutableStateOf("") |  | ||||||
|     private var projectDescriptionProperty by mutableStateOf("") |  | ||||||
|     private var projectUrlProperty by mutableStateOf("") |  | ||||||
|     private var projectVcsUrlProperty by mutableStateOf("") |  | ||||||
|     private var includeGpgSignProperty by mutableStateOf(true) |  | ||||||
|     private var publishToMavenCentralProperty by mutableStateOf(false) |  | ||||||
|     private val developersView = DevelopersView() |  | ||||||
|     private val repositoriesView = RepositoriesView() |  | ||||||
|  |  | ||||||
|     var mavenConfig: MavenConfig |  | ||||||
|         get() = MavenConfig( |  | ||||||
|             projectNameProperty, |  | ||||||
|             projectDescriptionProperty, |  | ||||||
|             projectUrlProperty, |  | ||||||
|             projectVcsUrlProperty, |  | ||||||
|             includeGpgSignProperty, |  | ||||||
|             developersView.developers, |  | ||||||
|             repositoriesView.repositories + if (publishToMavenCentralProperty) { |  | ||||||
|                 listOf(SonatypeRepository) |  | ||||||
|             } else { |  | ||||||
|                 emptyList() |  | ||||||
|             } |  | ||||||
|         ) |  | ||||||
|         set(value) { |  | ||||||
|             projectNameProperty = value.name |  | ||||||
|             projectDescriptionProperty = value.description |  | ||||||
|             projectUrlProperty = value.url |  | ||||||
|             projectVcsUrlProperty = value.vcsUrl |  | ||||||
|             includeGpgSignProperty = value.includeGpgSigning |  | ||||||
|             publishToMavenCentralProperty = value.repositories.any { it == SonatypeRepository } |  | ||||||
|             developersView.developers = value.developers |  | ||||||
|             repositoriesView.repositories = value.repositories.filter { it != SonatypeRepository } |  | ||||||
| //            developersView.developers = value.developers |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     override val content: @Composable ColumnScope.() -> Unit = { |  | ||||||
|         CommonTextField( |  | ||||||
|             projectNameProperty, |  | ||||||
|             "Public project name" |  | ||||||
|         ) { projectNameProperty = it } |  | ||||||
|         CommonTextField( |  | ||||||
|             projectDescriptionProperty, |  | ||||||
|             "Public project description" |  | ||||||
|         ) { projectDescriptionProperty = it } |  | ||||||
|         CommonTextField( |  | ||||||
|             projectUrlProperty, |  | ||||||
|             "Public project URL" |  | ||||||
|         ) { projectUrlProperty = it } |  | ||||||
|         CommonTextField( |  | ||||||
|             projectVcsUrlProperty, |  | ||||||
|             "Public project VCS URL (with .git)" |  | ||||||
|         ) { projectVcsUrlProperty = it } |  | ||||||
|  |  | ||||||
|         SwitchWithLabel( |  | ||||||
|             "Include GPG Signing", |  | ||||||
|             includeGpgSignProperty, |  | ||||||
|             placeSwitchAtTheStart = true |  | ||||||
|         ) { includeGpgSignProperty = it } |  | ||||||
|  |  | ||||||
|         SwitchWithLabel( |  | ||||||
|             "Include publication to MavenCentral", |  | ||||||
|             publishToMavenCentralProperty, |  | ||||||
|             placeSwitchAtTheStart = true |  | ||||||
|         ) { publishToMavenCentralProperty = it } |  | ||||||
|         developersView.init() |  | ||||||
|         repositoriesView.init() |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,33 +0,0 @@ | |||||||
| package dev.inmo.kmppscriptbuilder.desktop.views |  | ||||||
|  |  | ||||||
| import androidx.compose.foundation.layout.* |  | ||||||
| import androidx.compose.material.Switch |  | ||||||
| import androidx.compose.material.Text |  | ||||||
| import androidx.compose.runtime.* |  | ||||||
| import androidx.compose.ui.Modifier |  | ||||||
| import androidx.compose.ui.unit.dp |  | ||||||
| import dev.inmo.kmppscriptbuilder.core.models.* |  | ||||||
| import dev.inmo.kmppscriptbuilder.desktop.utils.VerticalView |  | ||||||
|  |  | ||||||
| class ProjectTypeView : VerticalView("Project type") { |  | ||||||
|     private var projectTypeState by mutableStateOf<Boolean>(false) |  | ||||||
|     private val calculatedProjectType: ProjectType |  | ||||||
|         get() = if (projectTypeState) JVMProjectType else MultiplatformProjectType |  | ||||||
|     var projectType: ProjectType |  | ||||||
|         get() = calculatedProjectType |  | ||||||
|         set(value) { |  | ||||||
|             projectTypeState = value == JVMProjectType |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     override val content: @Composable ColumnScope.() -> Unit = { |  | ||||||
|         Row(horizontalArrangement = Arrangement.spacedBy(5.dp)) { |  | ||||||
|             Text("Multiplatform", Modifier.alignByBaseline()) |  | ||||||
|             Switch( |  | ||||||
|                 projectTypeState, |  | ||||||
|                 { projectTypeState = it }, |  | ||||||
|                 Modifier.padding(4.dp, 0.dp) |  | ||||||
|             ) |  | ||||||
|             Text("JVM", Modifier.alignByBaseline()) |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,45 +0,0 @@ | |||||||
| package dev.inmo.kmppscriptbuilder.desktop.views |  | ||||||
|  |  | ||||||
| import androidx.compose.runtime.* |  | ||||||
| import dev.inmo.kmppscriptbuilder.core.models.MavenPublishingRepository |  | ||||||
| import dev.inmo.kmppscriptbuilder.desktop.utils.* |  | ||||||
|  |  | ||||||
| class RepositoryState( |  | ||||||
|     name: String = "", |  | ||||||
|     url: String = "" |  | ||||||
| ) { |  | ||||||
|     var name: String by mutableStateOf(name) |  | ||||||
|     var url: String by mutableStateOf(url) |  | ||||||
|  |  | ||||||
|     fun toRepository() = MavenPublishingRepository(name, url) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| private fun MavenPublishingRepository.toRepositoryState() = RepositoryState(name, url) |  | ||||||
|  |  | ||||||
| class RepositoriesView : ListView<RepositoryState>("Repositories info") { |  | ||||||
|     var repositories: List<MavenPublishingRepository> |  | ||||||
|         get() = itemsList.map { it.toRepository() } |  | ||||||
|         set(value) { |  | ||||||
|             itemsList.clear() |  | ||||||
|             itemsList.addAll( |  | ||||||
|                 value.map { it.toRepositoryState() } |  | ||||||
|             ) |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     override val addItemText: String = "Add repository" |  | ||||||
|     override val removeItemText: String = "Remove repository" |  | ||||||
|  |  | ||||||
|     override fun createItem(): RepositoryState = RepositoryState() |  | ||||||
|     @Composable |  | ||||||
|     override fun buildView(item: RepositoryState) { |  | ||||||
|         CommonTextField( |  | ||||||
|             item.name, |  | ||||||
|             "Repository name" |  | ||||||
|         ) { item.name = it } |  | ||||||
|         CommonTextField( |  | ||||||
|             item.url, |  | ||||||
|             "Repository url" |  | ||||||
|         ) { item.url = it } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -16,7 +16,6 @@ allprojects { | |||||||
|         mppProjectWithSerializationPresetPath = "${rootProject.projectDir.absolutePath}/mppProjectWithSerialization.gradle" |         mppProjectWithSerializationPresetPath = "${rootProject.projectDir.absolutePath}/mppProjectWithSerialization.gradle" | ||||||
|         mppJavaProjectPresetPath = "${rootProject.projectDir.absolutePath}/mppJavaProject.gradle" |         mppJavaProjectPresetPath = "${rootProject.projectDir.absolutePath}/mppJavaProject.gradle" | ||||||
|         mppJsProjectPresetPath = "${rootProject.projectDir.absolutePath}/mppJsProject.gradle" |         mppJsProjectPresetPath = "${rootProject.projectDir.absolutePath}/mppJsProject.gradle" | ||||||
|         mppAndroidProjectPresetPath = "${rootProject.projectDir.absolutePath}/mppAndroidProject.gradle" |  | ||||||
|  |  | ||||||
|         defaultAndroidSettingsPresetPath = "${rootProject.projectDir.absolutePath}/defaultAndroidSettings.gradle" |         defaultAndroidSettingsPresetPath = "${rootProject.projectDir.absolutePath}/defaultAndroidSettings.gradle" | ||||||
|  |  | ||||||
|   | |||||||
| @@ -3,30 +3,6 @@ org.gradle.parallel=true | |||||||
| kotlin.js.generate.externals=true | kotlin.js.generate.externals=true | ||||||
| kotlin.incremental=true | kotlin.incremental=true | ||||||
| kotlin.incremental.js=true | kotlin.incremental.js=true | ||||||
| android.useAndroidX=true |  | ||||||
| android.enableJetifier=true |  | ||||||
|  |  | ||||||
| kotlin_version=1.4.30 |  | ||||||
| kotlin_coroutines_version=1.4.2 |  | ||||||
| kotlin_serialisation_core_version=1.1.0 |  | ||||||
| ktor_version=1.5.1 |  | ||||||
| micro_utils_version=0.4.27 |  | ||||||
|  |  | ||||||
| compose_version=0.3.0 |  | ||||||
|  |  | ||||||
| # ANDROID |  | ||||||
|  |  | ||||||
| android_minSdkVersion=21 |  | ||||||
| android_compileSdkVersion=30 |  | ||||||
| android_buildToolsVersion=30.0.2 |  | ||||||
| dexcount_version=2.0.0 |  | ||||||
| junit_version=4.12 |  | ||||||
| test_ext_junit_version=1.1.2 |  | ||||||
| espresso_core=3.3.0 |  | ||||||
|  |  | ||||||
| # Dokka |  | ||||||
|  |  | ||||||
| dokka_version=1.4.20 |  | ||||||
|  |  | ||||||
| # Project data | # Project data | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										45
									
								
								gradle/libs.versions.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,45 @@ | |||||||
|  | [versions] | ||||||
|  |  | ||||||
|  | kt = "1.9.20" | ||||||
|  | kt-serialization = "1.6.0" | ||||||
|  | kt-coroutines = "1.7.3" | ||||||
|  |  | ||||||
|  | jb-compose = "1.5.10" | ||||||
|  | jb-dokka = "1.9.10" | ||||||
|  | microutils = "0.20.11" | ||||||
|  | kjsuikit = "0.7.3" | ||||||
|  |  | ||||||
|  | ktor = "2.3.5" | ||||||
|  |  | ||||||
|  | gh-release = "2.4.1" | ||||||
|  |  | ||||||
|  | [libraries] | ||||||
|  |  | ||||||
|  | kt-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kt" } | ||||||
|  |  | ||||||
|  | kt-serialization = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kt-serialization" } | ||||||
|  |  | ||||||
|  | kt-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kt-coroutines" } | ||||||
|  |  | ||||||
|  | ktor-client = { module = "io.ktor:ktor-client-core", version.ref = "ktor" } | ||||||
|  | ktor-client-cio = { module = "io.ktor:ktor-client-cio", version.ref = "ktor" } | ||||||
|  | ktor-client-js = { module = "io.ktor:ktor-client-js", version.ref = "ktor" } | ||||||
|  |  | ||||||
|  | microutils-common = { module = "dev.inmo:micro_utils.common", version.ref = "microutils" } | ||||||
|  | microutils-coroutines = { module = "dev.inmo:micro_utils.coroutines", version.ref = "microutils" } | ||||||
|  |  | ||||||
|  | jsuikit = { module = "dev.inmo:kjsuikit", version.ref = "kjsuikit" } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | kt-test-js = { module = "org.jetbrains.kotlin:kotlin-test-js", version.ref = "kt" } | ||||||
|  | kt-test-junit = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kt" } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | buildscript-kt-gradle = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kt" } | ||||||
|  | buildscript-kt-serialization = { module = "org.jetbrains.kotlin:kotlin-serialization", version.ref = "kt" } | ||||||
|  | buildscript-jb-dokka = { module = "org.jetbrains.dokka:dokka-gradle-plugin", version.ref = "jb-dokka" } | ||||||
|  | buildscript-gh-release = { module = "com.github.breadmoirai:github-release", version.ref = "gh-release" } | ||||||
|  |  | ||||||
|  | [plugins] | ||||||
|  |  | ||||||
|  | jb-compose = { id = "org.jetbrains.compose", version.ref = "jb-compose" } | ||||||
							
								
								
									
										2
									
								
								gradle/wrapper/gradle-wrapper.properties
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME | |||||||
| distributionPath=wrapper/dists | distributionPath=wrapper/dists | ||||||
| zipStoreBase=GRADLE_USER_HOME | zipStoreBase=GRADLE_USER_HOME | ||||||
| zipStorePath=wrapper/dists | zipStorePath=wrapper/dists | ||||||
| distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip | distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip | ||||||
|   | |||||||
| @@ -4,9 +4,7 @@ project.group = "$group" | |||||||
| // apply from: "$publishGradlePath" | // apply from: "$publishGradlePath" | ||||||
|  |  | ||||||
| kotlin { | kotlin { | ||||||
|     jvm { |     jvm() | ||||||
|         compilations.main.kotlinOptions.useIR = true |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     sourceSets { |     sourceSets { | ||||||
|         commonMain { |         commonMain { | ||||||
|   | |||||||
| @@ -5,17 +5,15 @@ project.group = "$group" | |||||||
|  |  | ||||||
| kotlin { | kotlin { | ||||||
|     js (IR) { |     js (IR) { | ||||||
|         browser { |         browser() | ||||||
|             binaries.executable() |         binaries.executable() | ||||||
|         } |  | ||||||
|         nodejs() |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     sourceSets { |     sourceSets { | ||||||
|         commonMain { |         commonMain { | ||||||
|             dependencies { |             dependencies { | ||||||
|                 implementation kotlin('stdlib') |                 implementation kotlin('stdlib') | ||||||
|                 api "org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlin_serialisation_core_version" |                 api libs.kt.serialization | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         commonTest { |         commonTest { | ||||||
|   | |||||||
| @@ -1,25 +1,20 @@ | |||||||
| project.version = "$version" + System.getenv("additional_version") | project.version = "$version" + (System.getenv("additional_version") == null ? "" : System.getenv("additional_version")) | ||||||
| project.group = "$group" | project.group = "$group" | ||||||
|  |  | ||||||
| // apply from: "$publishGradlePath" | // apply from: "$publishGradlePath" | ||||||
|  |  | ||||||
| kotlin { | kotlin { | ||||||
|     jvm { |     jvm() | ||||||
|         compilations.main.kotlinOptions.useIR = true |  | ||||||
|     } |  | ||||||
|     js (IR) { |     js (IR) { | ||||||
|         browser() |         browser() | ||||||
|         nodejs() |         nodejs() | ||||||
|     } |     } | ||||||
|     android { |  | ||||||
|         publishAllLibraryVariants() |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     sourceSets { |     sourceSets { | ||||||
|         commonMain { |         commonMain { | ||||||
|             dependencies { |             dependencies { | ||||||
|                 implementation kotlin('stdlib') |                 implementation kotlin('stdlib') | ||||||
|                 api "org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlin_serialisation_core_version" |                 api libs.kt.serialization | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         commonTest { |         commonTest { | ||||||
| @@ -39,14 +34,5 @@ kotlin { | |||||||
|                 implementation kotlin('test-junit') |                 implementation kotlin('test-junit') | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         androidTest { |  | ||||||
|             dependencies { |  | ||||||
|                 implementation kotlin('test-junit') |  | ||||||
|                 implementation "androidx.test.ext:junit:$test_ext_junit_version" |  | ||||||
|                 implementation "androidx.test.espresso:espresso-core:$espresso_core" |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| apply from: "$defaultAndroidSettingsPresetPath" |  | ||||||
|   | |||||||
| @@ -9,8 +9,8 @@ rootProject.name = 'kmppscriptbuilder' | |||||||
|  |  | ||||||
| String[] includes = [ | String[] includes = [ | ||||||
|         ":core", |         ":core", | ||||||
|         ":desktop", | //        ":desktop", | ||||||
|         ":web" | //        ":web" | ||||||
| ] | ] | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,17 +0,0 @@ | |||||||
| plugins { |  | ||||||
|     id "org.jetbrains.kotlin.multiplatform" |  | ||||||
|     id "org.jetbrains.kotlin.plugin.serialization" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| apply from: "$mppJsProjectPresetPath" |  | ||||||
|  |  | ||||||
| kotlin { |  | ||||||
|     sourceSets { |  | ||||||
|         commonMain { |  | ||||||
|             dependencies { |  | ||||||
|                 implementation project(":kmppscriptbuilder.core") |  | ||||||
|                 implementation "dev.inmo:micro_utils.common:$micro_utils_version" |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,82 +0,0 @@ | |||||||
| package dev.inmo.kmppscriptbuilder.web |  | ||||||
|  |  | ||||||
| import dev.inmo.kmppscriptbuilder.core.models.Config |  | ||||||
| import dev.inmo.kmppscriptbuilder.core.utils.serialFormat |  | ||||||
| import dev.inmo.kmppscriptbuilder.web.views.* |  | ||||||
| import kotlinx.browser.document |  | ||||||
| import kotlinx.dom.appendElement |  | ||||||
| import org.w3c.dom.* |  | ||||||
| import org.w3c.dom.url.URL |  | ||||||
| import org.w3c.files.* |  | ||||||
|  |  | ||||||
| fun saveFile(content: String, filename: String) { |  | ||||||
|     val a = document.body!!.appendElement("a") { |  | ||||||
|         setAttribute("style", "visibility:hidden; display: none") |  | ||||||
|     } as HTMLAnchorElement |  | ||||||
|     val blob = Blob(arrayOf(content), BlobPropertyBag( |  | ||||||
|         "application/*;charset=utf-8" |  | ||||||
|     )) |  | ||||||
|     val url = URL.createObjectURL(blob) |  | ||||||
|     a.href = url |  | ||||||
|     a.download = filename |  | ||||||
|     a.click() |  | ||||||
|     URL.revokeObjectURL(url) |  | ||||||
|     a.remove() |  | ||||||
| } |  | ||||||
|  |  | ||||||
| fun main() { |  | ||||||
|     document.addEventListener( |  | ||||||
|         "DOMContentLoaded", |  | ||||||
|         { |  | ||||||
|             val builderView = BuilderView() |  | ||||||
|  |  | ||||||
|             (document.getElementById("openConfig") as HTMLElement).onclick = { |  | ||||||
|                 val targetInput = document.body!!.appendElement("input") { |  | ||||||
|                     setAttribute("style", "visibility:hidden; display: none") |  | ||||||
|                 } as HTMLInputElement |  | ||||||
|                 targetInput.type = "file" |  | ||||||
|                 targetInput.onchange = { |  | ||||||
|                     targetInput.files ?.also { files -> |  | ||||||
|                         for (i in (0 until files.length) ) { |  | ||||||
|                             files[i] ?.also { file -> |  | ||||||
|                                 val reader = FileReader() |  | ||||||
|  |  | ||||||
|                                 reader.onload = { |  | ||||||
|                                     val content = it.target.asDynamic().result as String |  | ||||||
|                                     builderView.config = serialFormat.decodeFromString(Config.serializer(), content) |  | ||||||
|                                     false |  | ||||||
|                                 } |  | ||||||
|  |  | ||||||
|                                 reader.readAsText(file) |  | ||||||
|                             } |  | ||||||
|                         } |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|                 targetInput.click() |  | ||||||
|                 targetInput.remove() |  | ||||||
|                 false |  | ||||||
|             } |  | ||||||
|             (document.getElementById("saveConfig") as HTMLElement).onclick = { |  | ||||||
|                 val filename = "publish.kpsb" |  | ||||||
|                 val content = serialFormat.encodeToString(Config.serializer(), builderView.config) |  | ||||||
|  |  | ||||||
|                 saveFile(content, filename) |  | ||||||
|  |  | ||||||
|                 false |  | ||||||
|             } |  | ||||||
|             (document.getElementById("exportScript") as HTMLElement).onclick = { |  | ||||||
|                 val filename = "publish.gradle" |  | ||||||
|  |  | ||||||
|                 val content = builderView.config.run { |  | ||||||
|                     type.buildMavenGradleConfig( |  | ||||||
|                         mavenConfig, |  | ||||||
|                         licenses |  | ||||||
|                     ) |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 saveFile(content, filename) |  | ||||||
|                 false |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     ) |  | ||||||
| } |  | ||||||
| @@ -1,13 +0,0 @@ | |||||||
| package dev.inmo.kmppscriptbuilder.web.utils |  | ||||||
|  |  | ||||||
| import org.w3c.dom.HTMLElement |  | ||||||
|  |  | ||||||
| var HTMLElement.ukActive: Boolean |  | ||||||
|     get() = classList.contains("uk-active") |  | ||||||
|     set(value) { |  | ||||||
|         if (value) { |  | ||||||
|             classList.add("uk-active") |  | ||||||
|         } else { |  | ||||||
|             classList.remove("uk-active") |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| @@ -1,10 +0,0 @@ | |||||||
| package dev.inmo.kmppscriptbuilder.web.utils |  | ||||||
|  |  | ||||||
| import kotlinx.browser.document |  | ||||||
|  |  | ||||||
| inline fun <R> keepScrolling(crossinline block: () -> R): R = document.body ?.let { |  | ||||||
|     val (x, y) = (it.scrollLeft to it.scrollTop) |  | ||||||
|     return block().also { _ -> |  | ||||||
|         it.scrollTo(x, y) |  | ||||||
|     } |  | ||||||
| } ?: block() |  | ||||||
| @@ -1,23 +0,0 @@ | |||||||
| package dev.inmo.kmppscriptbuilder.web.views |  | ||||||
|  |  | ||||||
| import dev.inmo.kmppscriptbuilder.core.models.Config |  | ||||||
| import kotlinx.browser.document |  | ||||||
| import org.w3c.dom.HTMLElement |  | ||||||
|  |  | ||||||
| class BuilderView : View { |  | ||||||
|     private val projectTypeView = ProjectTypeView() |  | ||||||
|     private val licensesView = LicensesView(document.getElementById("licensesListDiv") as HTMLElement) |  | ||||||
|     private val mavenInfoTypeView = MavenProjectInfoView() |  | ||||||
|  |  | ||||||
|     var config: Config |  | ||||||
|         get() = Config( |  | ||||||
|             licensesView.licenses, |  | ||||||
|             mavenInfoTypeView.mavenConfig, |  | ||||||
|             projectTypeView.projectType |  | ||||||
|         ) |  | ||||||
|         set(value) { |  | ||||||
|             licensesView.licenses = value.licenses |  | ||||||
|             mavenInfoTypeView.mavenConfig = value.mavenConfig |  | ||||||
|             projectTypeView.projectType = value.type |  | ||||||
|         } |  | ||||||
| } |  | ||||||
| @@ -1,35 +0,0 @@ | |||||||
| package dev.inmo.kmppscriptbuilder.web.views |  | ||||||
|  |  | ||||||
| import dev.inmo.kmppscriptbuilder.core.models.Developer |  | ||||||
| import org.w3c.dom.* |  | ||||||
|  |  | ||||||
| class DevelopersView(rootElement: HTMLElement) : MutableListView<Developer>(rootElement, "Add developer", "Remove developer") { |  | ||||||
|     private val HTMLElement.usernameElement: HTMLInputElement |  | ||||||
|         get() = getElementsByTagName("input")[0] as HTMLInputElement |  | ||||||
|     private val HTMLElement.nameElement: HTMLInputElement |  | ||||||
|         get() = getElementsByTagName("input")[1] as HTMLInputElement |  | ||||||
|     private val HTMLElement.emailElement: HTMLInputElement |  | ||||||
|         get() = getElementsByTagName("input")[2] as HTMLInputElement |  | ||||||
|  |  | ||||||
|     var developers: List<Developer> |  | ||||||
|         get() = elements.map { |  | ||||||
|             Developer(it.usernameElement.value, it.nameElement.value, it.emailElement.value) |  | ||||||
|         } |  | ||||||
|         set(value) { |  | ||||||
|             data = value |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     override fun createPlainObject(): Developer = Developer("", "", "") |  | ||||||
|  |  | ||||||
|     override fun HTMLElement.addContentBeforeRemoveButton(value: Developer) { |  | ||||||
|         createTextField("Developer ID", "Developer username").value = value.id |  | ||||||
|         createTextField("Developer name", "").value = value.name |  | ||||||
|         createTextField("Developer E-Mail", "").value = value.eMail |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     override fun HTMLElement.updateElement(from: Developer, to: Developer) { |  | ||||||
|         usernameElement.value = to.id |  | ||||||
|         nameElement.value = to.name |  | ||||||
|         emailElement.value = to.eMail |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,113 +0,0 @@ | |||||||
| package dev.inmo.kmppscriptbuilder.web.views |  | ||||||
|  |  | ||||||
| import dev.inmo.kmppscriptbuilder.core.models.License |  | ||||||
| import dev.inmo.kmppscriptbuilder.core.models.getLicenses |  | ||||||
| import dev.inmo.micro_utils.coroutines.safeActor |  | ||||||
| import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions |  | ||||||
| import io.ktor.client.HttpClient |  | ||||||
| import kotlinx.coroutines.* |  | ||||||
| import kotlinx.coroutines.channels.Channel |  | ||||||
| import kotlinx.coroutines.channels.SendChannel |  | ||||||
| import kotlinx.coroutines.flow.consumeAsFlow |  | ||||||
| import kotlinx.coroutines.flow.debounce |  | ||||||
| import kotlinx.dom.appendElement |  | ||||||
| import org.w3c.dom.* |  | ||||||
|  |  | ||||||
| class LicensesView( |  | ||||||
|     rootElement: HTMLElement, |  | ||||||
|     client: HttpClient = HttpClient(), |  | ||||||
|     scope: CoroutineScope = CoroutineScope(Dispatchers.Default) |  | ||||||
| ) : MutableListView<License>(rootElement, "Add empty license", "Remove license") { |  | ||||||
|     private val HTMLElement.idElement: HTMLInputElement |  | ||||||
|         get() = getElementsByTagName("input")[0] as HTMLInputElement |  | ||||||
|     private val HTMLElement.titleElement: HTMLInputElement |  | ||||||
|         get() = getElementsByTagName("input")[1] as HTMLInputElement |  | ||||||
|     private val HTMLElement.urlElement: HTMLInputElement |  | ||||||
|         get() = getElementsByTagName("input")[2] as HTMLInputElement |  | ||||||
|  |  | ||||||
|     private class LicenseOfferList( |  | ||||||
|         rootElement: HTMLElement, |  | ||||||
|         private val licensesView: LicensesView, |  | ||||||
|         client: HttpClient, |  | ||||||
|         scope: CoroutineScope |  | ||||||
|     ) : ListView<License>(rootElement, useSimpleDiffStrategy = true) { |  | ||||||
|         private var licensesTemplates: List<License> = emptyList() |  | ||||||
|  |  | ||||||
|         init { |  | ||||||
|             scope.launch { |  | ||||||
|                 licensesTemplates = client.getLicenses().values.toList() |  | ||||||
|                 changeActor.send(Unit) // update list of searches |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         private val changeActor: SendChannel<Unit> = scope.run { |  | ||||||
|             val onChangeActor = Channel<Unit>(Channel.CONFLATED) |  | ||||||
|             onChangeActor.consumeAsFlow().subscribeSafelyWithoutExceptions(scope) { |  | ||||||
|                 val lowercased = searchString |  | ||||||
|                 data = if (lowercased.isEmpty()) { |  | ||||||
|                     emptyList() |  | ||||||
|                 } else { |  | ||||||
|                     licensesTemplates.filter { |  | ||||||
|                         val lowercasedTitle = it.title.toLowerCase() |  | ||||||
|                         lowercased.all { it in lowercasedTitle } |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             onChangeActor |  | ||||||
|         } |  | ||||||
|         private val searchElement = rootElement.createTextField("Quick add", "Type some license name part to find it").apply { |  | ||||||
|             oninput = { |  | ||||||
|                 changeActor.offer(Unit) |  | ||||||
|                 false |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         private var searchString: String |  | ||||||
|             get() = searchElement.value.toLowerCase() |  | ||||||
|             set(value) { |  | ||||||
|                 searchElement.value = value |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|         override fun HTMLElement.placeElement(value: License) { |  | ||||||
|             createCommonButton(value.title).onclick = { |  | ||||||
|                 searchString = "" |  | ||||||
|                 licensesView.licenses += value |  | ||||||
|                 changeActor.offer(Unit) |  | ||||||
|                 false |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         override fun HTMLElement.updateElement(from: License, to: License) { |  | ||||||
|             getElementsByTagName("button")[0] ?.remove() |  | ||||||
|             placeElement(to) |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private val licensesOffersList = LicenseOfferList( |  | ||||||
|         rootElement.appendElement("div") { classList.add("uk-padding-small") } as HTMLElement, |  | ||||||
|         this, |  | ||||||
|         client, |  | ||||||
|         scope |  | ||||||
|     ) |  | ||||||
|  |  | ||||||
|     var licenses: List<License> |  | ||||||
|         get() = elements.map { |  | ||||||
|             License(it.idElement.value, it.titleElement.value, it.urlElement.value) |  | ||||||
|         } |  | ||||||
|         set(value) { |  | ||||||
|             data = value |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     override fun createPlainObject(): License = License("", "", "") |  | ||||||
|  |  | ||||||
|     override fun HTMLElement.addContentBeforeRemoveButton(value: License) { |  | ||||||
|         createTextField("License Id", "Short name like \"Apache-2.0\"").value = value.id |  | ||||||
|         createTextField("License Title", "Official title of license (like \"Apache Software License 2.0\")").value = value.title |  | ||||||
|         createTextField("License URL", "Link to your LICENSE file OR official license file (like \"https://opensource.org/licenses/Apache-2.0\")").value = value.url ?: "" |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     override fun HTMLElement.updateElement(from: License, to: License) { |  | ||||||
|         idElement.value = to.id |  | ||||||
|         titleElement.value = to.title |  | ||||||
|         urlElement.value = to.url ?: "" |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,58 +0,0 @@ | |||||||
| package dev.inmo.kmppscriptbuilder.web.views |  | ||||||
|  |  | ||||||
| import dev.inmo.micro_utils.common.calculateStrictDiff |  | ||||||
| import kotlinx.dom.appendElement |  | ||||||
| import org.w3c.dom.HTMLElement |  | ||||||
|  |  | ||||||
| abstract class ListView<T>( |  | ||||||
|     protected val rootElement: HTMLElement, |  | ||||||
|     useSimpleDiffStrategy: Boolean = false |  | ||||||
| ) : View { |  | ||||||
|     protected val elements = mutableListOf<HTMLElement>() |  | ||||||
|     private val diffHandling: (old: List<T>, new: List<T>) -> Unit = if (useSimpleDiffStrategy) { |  | ||||||
|         { _, new -> |  | ||||||
|             elements.forEach { it.remove() } |  | ||||||
|             elements.clear() |  | ||||||
|             new.forEach { |  | ||||||
|                 val element = instantiateElement() |  | ||||||
|                 elements.add(element) |  | ||||||
|                 element.placeElement(it) |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } else { |  | ||||||
|         {  old, new -> |  | ||||||
|             val diff = old.calculateStrictDiff(new) |  | ||||||
|             diff.removed.forEach { |  | ||||||
|                 elements[it.index].remove() |  | ||||||
|                 elements.removeAt(it.index) |  | ||||||
|                 println(it.value) |  | ||||||
|             } |  | ||||||
|             diff.added.forEach { |  | ||||||
|                 val element = instantiateElement() |  | ||||||
|                 elements.add(element) |  | ||||||
|                 element.placeElement(it.value) |  | ||||||
|             } |  | ||||||
|             diff.replaced.forEach { (old, new) -> |  | ||||||
|                 val element = elements.getOrNull(old.index) ?.also { it.updateElement(old.value, new.value) } |  | ||||||
|                 if (element == null) { |  | ||||||
|                     val newElement = instantiateElement() |  | ||||||
|                     newElement.placeElement(new.value) |  | ||||||
|                     elements[new.index] = newElement |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     protected var data: List<T> = emptyList() |  | ||||||
|         set(value) { |  | ||||||
|             val old = field |  | ||||||
|             field = value |  | ||||||
|             diffHandling(old, value) |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     protected abstract fun HTMLElement.placeElement(value: T) |  | ||||||
|     protected abstract fun HTMLElement.updateElement(from: T, to: T) |  | ||||||
|  |  | ||||||
|     private fun instantiateElement() = rootElement.appendElement("div") { |  | ||||||
|         classList.add("uk-padding-small") |  | ||||||
|     } as HTMLElement |  | ||||||
| } |  | ||||||
| @@ -1,44 +0,0 @@ | |||||||
| package dev.inmo.kmppscriptbuilder.web.views |  | ||||||
|  |  | ||||||
| import dev.inmo.kmppscriptbuilder.core.models.MavenConfig |  | ||||||
| import dev.inmo.kmppscriptbuilder.core.models.SonatypeRepository |  | ||||||
| import kotlinx.browser.document |  | ||||||
| import org.w3c.dom.HTMLElement |  | ||||||
| import org.w3c.dom.HTMLInputElement |  | ||||||
|  |  | ||||||
| class MavenProjectInfoView : View { |  | ||||||
|     private val nameElement = document.getElementById("projectNameInput") as HTMLInputElement |  | ||||||
|     private val descriptionElement = document.getElementById("projectDescriptionInput") as HTMLInputElement |  | ||||||
|     private val urlElement = document.getElementById("projectUrlInput") as HTMLInputElement |  | ||||||
|     private val vcsUrlElement = document.getElementById("projectVCSUrlInput") as HTMLInputElement |  | ||||||
|     private val includeGpgElement = document.getElementById("includeGpgSignToggle") as HTMLInputElement |  | ||||||
|     private val includeMavenCentralElement = document.getElementById("includeMavenCentralTargetRepoToggle") as HTMLInputElement |  | ||||||
|     private val developersView = DevelopersView(document.getElementById("developersListDiv") as HTMLElement) |  | ||||||
|     private val repositoriesView = RepositoriesView(document.getElementById("repositoriesListDiv") as HTMLElement) |  | ||||||
|  |  | ||||||
|     var mavenConfig: MavenConfig |  | ||||||
|         get() = MavenConfig( |  | ||||||
|             nameElement.value, |  | ||||||
|             descriptionElement.value, |  | ||||||
|             urlElement.value, |  | ||||||
|             vcsUrlElement.value, |  | ||||||
|             includeGpgElement.checked, |  | ||||||
|             developersView.developers, |  | ||||||
|             repositoriesView.repositories + if (includeMavenCentralElement.checked) { |  | ||||||
|                 listOf(SonatypeRepository) |  | ||||||
|             } else { |  | ||||||
|                 emptyList() |  | ||||||
|             } |  | ||||||
|         ) |  | ||||||
|         set(value) { |  | ||||||
|             nameElement.value = value.name |  | ||||||
|             descriptionElement.value = value.description |  | ||||||
|             urlElement.value = value.url |  | ||||||
|             vcsUrlElement.value = value.vcsUrl |  | ||||||
|             includeGpgElement.checked = value.includeGpgSigning |  | ||||||
|             developersView.developers = value.developers |  | ||||||
|             val reposWithoutSonatype = value.repositories.filter { it != SonatypeRepository } |  | ||||||
|             includeMavenCentralElement.checked = value.repositories.size != reposWithoutSonatype.size |  | ||||||
|             repositoriesView.repositories = value.repositories |  | ||||||
|         } |  | ||||||
| } |  | ||||||
| @@ -1,41 +0,0 @@ | |||||||
| package dev.inmo.kmppscriptbuilder.web.views |  | ||||||
|  |  | ||||||
| import dev.inmo.kmppscriptbuilder.web.utils.keepScrolling |  | ||||||
| import org.w3c.dom.HTMLElement |  | ||||||
|  |  | ||||||
| abstract class MutableListView<T>( |  | ||||||
|     rootElement: HTMLElement, |  | ||||||
|     addButtonText: String = "Add", |  | ||||||
|     private val removeButtonText: String = "Remove" |  | ||||||
| ) : ListView<T>(rootElement) { |  | ||||||
|     init { |  | ||||||
|         rootElement.createPrimaryButton(addButtonText).apply { |  | ||||||
|             onclick = { |  | ||||||
|                 keepScrolling { |  | ||||||
|                     val newObject = createPlainObject() |  | ||||||
|                     data += newObject |  | ||||||
|                 } |  | ||||||
|                 false |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     protected abstract fun createPlainObject(): T |  | ||||||
|     protected open fun HTMLElement.addContentBeforeRemoveButton(value: T) {} |  | ||||||
|     protected open fun HTMLElement.addContentAfterRemoveButton(value: T) {} |  | ||||||
|     final override fun HTMLElement.placeElement(value: T) { |  | ||||||
|         addContentBeforeRemoveButton(value) |  | ||||||
|         addRemoveButton() |  | ||||||
|         addContentAfterRemoveButton(value) |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private fun HTMLElement.addRemoveButton() { |  | ||||||
|         val button = createPrimaryButton(removeButtonText) |  | ||||||
|         button.onclick = { |  | ||||||
|             elements.indexOf(button.parentElement).takeIf { it > -1 } ?.also { |  | ||||||
|                 data -= data[it] |  | ||||||
|             } ?: rootElement.removeChild(this@addRemoveButton) |  | ||||||
|             false |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,33 +0,0 @@ | |||||||
| package dev.inmo.kmppscriptbuilder.web.views |  | ||||||
|  |  | ||||||
| import dev.inmo.kmppscriptbuilder.core.models.* |  | ||||||
| import dev.inmo.kmppscriptbuilder.web.utils.ukActive |  | ||||||
| import kotlinx.browser.document |  | ||||||
| import org.w3c.dom.HTMLElement |  | ||||||
|  |  | ||||||
| class ProjectTypeView : View { |  | ||||||
|     private val mppProjectTypeElement = document.getElementById("mppProjectType") as HTMLElement |  | ||||||
|     private val jvmProjectTypeElement = document.getElementById("jvmProjectType") as HTMLElement |  | ||||||
|  |  | ||||||
|     var projectType: ProjectType |  | ||||||
|         get() = if (jvmProjectTypeElement.ukActive) { |  | ||||||
|             JVMProjectType |  | ||||||
|         } else { |  | ||||||
|             MultiplatformProjectType |  | ||||||
|         } |  | ||||||
|         set(value) { |  | ||||||
|             mppProjectTypeElement.ukActive = value == MultiplatformProjectType |  | ||||||
|             jvmProjectTypeElement.ukActive = value == JVMProjectType |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     init { |  | ||||||
|         mppProjectTypeElement.onclick = { |  | ||||||
|             projectType = MultiplatformProjectType |  | ||||||
|             Unit |  | ||||||
|         } |  | ||||||
|         jvmProjectTypeElement.onclick = { |  | ||||||
|             projectType = JVMProjectType |  | ||||||
|             Unit |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,31 +0,0 @@ | |||||||
| package dev.inmo.kmppscriptbuilder.web.views |  | ||||||
|  |  | ||||||
| import dev.inmo.kmppscriptbuilder.core.models.MavenPublishingRepository |  | ||||||
| import org.w3c.dom.* |  | ||||||
|  |  | ||||||
| class RepositoriesView(rootElement: HTMLElement) : MutableListView<MavenPublishingRepository>(rootElement, "Add repository", "Remove repository") { |  | ||||||
|     private val HTMLElement.nameElement: HTMLInputElement |  | ||||||
|         get() = getElementsByTagName("input")[0] as HTMLInputElement |  | ||||||
|     private val HTMLElement.urlElement: HTMLInputElement |  | ||||||
|         get() = getElementsByTagName("input")[1] as HTMLInputElement |  | ||||||
|  |  | ||||||
|     var repositories: List<MavenPublishingRepository> |  | ||||||
|         get() = elements.map { |  | ||||||
|             MavenPublishingRepository(it.nameElement.value, it.urlElement.value) |  | ||||||
|         } |  | ||||||
|         set(value) { |  | ||||||
|             data = value |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     override fun createPlainObject(): MavenPublishingRepository = MavenPublishingRepository("", "") |  | ||||||
|  |  | ||||||
|     override fun HTMLElement.addContentBeforeRemoveButton(value: MavenPublishingRepository) { |  | ||||||
|         createTextField("Repository name", "This name will be used to identify repository in grade").value = value.name |  | ||||||
|         createTextField("Repository URL", "For example: https://repo.maven.apache.org/maven2/").value = value.name |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     override fun HTMLElement.updateElement(from: MavenPublishingRepository, to: MavenPublishingRepository) { |  | ||||||
|         nameElement.value = to.name |  | ||||||
|         urlElement.value = to.url |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,3 +0,0 @@ | |||||||
| package dev.inmo.kmppscriptbuilder.web.views |  | ||||||
|  |  | ||||||
| interface View |  | ||||||
| @@ -1,35 +0,0 @@ | |||||||
| package dev.inmo.kmppscriptbuilder.web.views |  | ||||||
|  |  | ||||||
| import kotlinx.dom.appendElement |  | ||||||
| import org.w3c.dom.* |  | ||||||
|  |  | ||||||
| fun HTMLElement.createTextField( |  | ||||||
|     label: String, |  | ||||||
|     placeholder: String |  | ||||||
| ): HTMLInputElement { |  | ||||||
|     return appendElement("div") { |  | ||||||
|         classList.add("uk-margin", "uk-width-1-1") |  | ||||||
|     }.appendElement("label") { |  | ||||||
|         classList.add("uk-form-label") |  | ||||||
|         innerHTML = label |  | ||||||
|     }.run { |  | ||||||
|         val input = appendElement("input") { |  | ||||||
|             classList.add("uk-input", "uk-width-expand") |  | ||||||
|             setAttribute("type", "text") |  | ||||||
|             setAttribute("placeholder", placeholder) |  | ||||||
|         } as HTMLInputElement |  | ||||||
|         input |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| fun HTMLElement.createPrimaryButton(text: String): HTMLButtonElement = (appendElement("button") { |  | ||||||
|     classList.add("uk-button", "uk-button-primary") |  | ||||||
| } as HTMLButtonElement).apply { |  | ||||||
|     innerText = text |  | ||||||
| } |  | ||||||
|  |  | ||||||
| fun HTMLElement.createCommonButton(text: String): HTMLButtonElement = (appendElement("button") { |  | ||||||
|     classList.add("uk-button", "uk-button-default") |  | ||||||
| } as HTMLButtonElement).apply { |  | ||||||
|     innerText = text |  | ||||||
| } |  | ||||||
| @@ -1,81 +0,0 @@ | |||||||
| <!DOCTYPE html> |  | ||||||
| <html lang="en"> |  | ||||||
| <head> |  | ||||||
|     <meta charset="UTF-8"> |  | ||||||
|     <title>Kotlin Publication Scripts Builder</title> |  | ||||||
|     <!-- UIkit CSS --> |  | ||||||
|     <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/uikit@3.6.17/dist/css/uikit.min.css" /> |  | ||||||
| </head> |  | ||||||
| <body> |  | ||||||
|     <nav class="uk-navbar-container" uk-navbar> |  | ||||||
|         <div class="uk-navbar-left"> |  | ||||||
|             <div class="uk-padding-small uk-text-lead">Kotlin Publication Scripts Builder</div> |  | ||||||
|             <div class="uk-padding-small"><a href="https://github.com/InsanusMokrassar/KotlinPublicationScriptsBuilder"><img src="https://img.shields.io/github/stars/InsanusMokrassar/KotlinPublicationScriptsBuilder?label=Github&style=plastic"/></a></div> |  | ||||||
|         </div> |  | ||||||
|         <div class="uk-navbar-right"> |  | ||||||
|             <ul class="uk-navbar-nav"> |  | ||||||
|                 <li uk-tooltip="title: Open config" id="openConfig"><a href="#"><span uk-icon="icon: pull"></span></a></li><!--Open file--> |  | ||||||
|                 <li uk-tooltip="title: Save config" id="saveConfig"><a href="#"><span uk-icon="icon: push"></span></a></li><!--Save file--> |  | ||||||
|                 <li uk-tooltip="title: Export script" id="exportScript"><a href="#"><span uk-icon="icon: upload"></span></a></li><!--Save file--> |  | ||||||
|             </ul> |  | ||||||
|         </div> |  | ||||||
|     </nav> |  | ||||||
|     <form class="uk-padding-small"> |  | ||||||
|         <fieldset class="uk-fieldset"> |  | ||||||
|             <legend class="uk-legend">Project type</legend> |  | ||||||
|             <div class="uk-padding-small"> |  | ||||||
|                 <ul class="uk-subnav uk-subnav-pill"> |  | ||||||
|                     <li id="mppProjectType" class="uk-active"><a href="#">Multiplatform</a></li> |  | ||||||
|                     <li id="jvmProjectType"><a href="#">JVM</a></li> |  | ||||||
|                 </ul> |  | ||||||
|             </div> |  | ||||||
|             <legend class="uk-legend">Licenses</legend> |  | ||||||
|             <div id="licensesListDiv" class="uk-padding-small"> |  | ||||||
| <!--                <div class="uk-margin uk-width-1-1">--> |  | ||||||
| <!--                    <input id="searchFilterInput" class="uk-input uk-width-expand" type="text" placeholder="License search filter">--> |  | ||||||
| <!--                </div>--> |  | ||||||
| <!--                <button class="uk-button uk-button-primary">Add empty license</button>--> |  | ||||||
|             </div> |  | ||||||
|  |  | ||||||
|             <legend class="uk-legend">Project information</legend> |  | ||||||
|  |  | ||||||
|             <div class="uk-padding-small"> |  | ||||||
|                 <div class="uk-margin uk-width-1-1"> |  | ||||||
|                     <label class="uk-form-label" for="projectNameInput">Public project name</label> |  | ||||||
|                     <input id="projectNameInput" class="uk-input uk-width-expand" type="text" placeholder="${project.name}"> |  | ||||||
|                 </div> |  | ||||||
|                 <div class="uk-margin uk-width-1-1"> |  | ||||||
|                     <label class="uk-form-label" for="projectDescriptionInput">Public project description</label> |  | ||||||
|                     <input id="projectDescriptionInput" class="uk-input uk-width-expand" type="text" placeholder="${project.name}"> |  | ||||||
|                 </div> |  | ||||||
|                 <div class="uk-margin uk-width-1-1"> |  | ||||||
|                     <label class="uk-form-label" for="projectUrlInput">Public project URL</label> |  | ||||||
|                     <input id="projectUrlInput" class="uk-input uk-width-expand" type="text" placeholder="Type url to github or other source with readme"> |  | ||||||
|                 </div> |  | ||||||
|                 <div class="uk-margin uk-width-1-1"> |  | ||||||
|                     <label class="uk-form-label" for="projectVCSUrlInput">Public project VCS URL (with .git)</label> |  | ||||||
|                     <input id="projectVCSUrlInput" class="uk-input uk-width-expand" type="text" placeholder="Type url to github .git file"> |  | ||||||
|                 </div> |  | ||||||
|  |  | ||||||
|                 <div class="uk-margin"> |  | ||||||
|                     <label><input id="includeGpgSignToggle" class="uk-checkbox" type="checkbox" checked> Include GPG Signing</label> |  | ||||||
|                 </div> |  | ||||||
|                 <div class="uk-margin"> |  | ||||||
|                     <label><input id="includeMavenCentralTargetRepoToggle" class="uk-checkbox" type="checkbox"> Include publication to MavenCentral</label> |  | ||||||
|                 </div> |  | ||||||
|             </div> |  | ||||||
|  |  | ||||||
|             <legend class="uk-legend">Developers info</legend> |  | ||||||
|             <div id="developersListDiv" class="uk-padding-small"></div> |  | ||||||
|  |  | ||||||
|             <legend class="uk-legend">Repositories info</legend> |  | ||||||
|             <div id="repositoriesListDiv" class="uk-padding-small"></div> |  | ||||||
|         </fieldset> |  | ||||||
|     </form> |  | ||||||
|     <!-- UIkit JS --> |  | ||||||
|     <script src="https://cdn.jsdelivr.net/npm/uikit@3.6.17/dist/js/uikit.min.js"></script> |  | ||||||
|     <script src="https://cdn.jsdelivr.net/npm/uikit@3.6.17/dist/js/uikit-icons.min.js"></script> |  | ||||||
|     <!-- Internal JS --> |  | ||||||
|     <script src="kmppscriptbuilder.web.js"></script> |  | ||||||
| </body> |  | ||||||
| </html> |  | ||||||