Compare commits

...

45 Commits

Author SHA1 Message Date
87f77543e2 fix of sign script generation 2023-11-05 13:39:52 +06:00
429f2176f2 update kjsuikit 2023-11-02 22:40:23 +06:00
a56b8ae2b5
Update MavenTemplater.kt 2023-11-02 18:32:19 +06:00
4324620932 fix of web publication 2023-11-02 17:43:12 +06:00
265e839dc7 fix of build 2023-11-02 17:40:56 +06:00
2144ca2cca update to support gradle 8.+ 2023-11-02 17:30:42 +06:00
bf21f92c6f update dependencies 2023-07-10 15:00:35 +06:00
41e8d2c540 update dependencies 2023-04-27 16:45:44 +06:00
047f51fd96 hotfix for header authorization 2022-11-16 21:19:01 +06:00
08da50705c more fixes of workflows to the god of workflows fixes 2022-11-16 20:39:28 +06:00
3c216af814 more fixes of workflows to the god of workflows fixes 2022-11-16 20:35:38 +06:00
6b5ab5acba
Update commit-release.yml 2022-11-16 20:34:08 +06:00
f723d55d7e update workflows 2022-11-16 18:39:28 +06:00
c0d0b7521e
Update commit-release.yml 2022-11-16 18:22:53 +06:00
7536c67589
Merge pull request #6 from InsanusMokrassar/different_credentials_support
Different credentials support
2022-11-16 17:59:41 +06:00
0770772e7d fix of workflows 2022-11-16 17:58:35 +06:00
c6b1289f5a complete 2022-11-16 17:54:16 +06:00
788fe49aa4 almost completed adding of new creds type UI 2022-11-16 16:45:48 +06:00
3be0f24eac complete restyling 2022-11-16 13:21:59 +06:00
9fe7c458e9 complete rework 2022-11-16 01:28:34 +06:00
8430e68167 total rework 2022-11-16 00:56:24 +06:00
53a76c7a73 temporal progress 2022-11-15 19:55:54 +06:00
70baa30127 partially go over with compose 2022-11-15 18:53:59 +06:00
283bc5acb4 start 2022-11-10 23:48:59 +06:00
26a5d20e26 add singAll task for cases when publishing script is generating with signing 2022-01-04 23:11:59 +06:00
ca1a91e0f0 small fixes in formatting 2022-01-04 22:54:50 +06:00
26fe225577 update desktop part 2022-01-04 22:47:37 +06:00
9a95bddf08 add support of JS publish scripts 2022-01-04 21:49:16 +06:00
c880d8e657 updates 2022-01-04 19:46:47 +06:00
ac87a140cc fixes 2021-09-04 19:34:24 +06:00
0dbe3a866b dependencies update 2021-09-04 19:09:16 +06:00
7c50c58a90 fix 2021-05-01 20:22:12 +06:00
ceff1eb1ef updates 2021-05-01 20:12:06 +06:00
46d6d429bb one more fix for web 2021-03-14 21:53:26 +06:00
dd9e71c9a2 fix in web view for loading of config 2021-03-14 21:46:41 +06:00
6d2ffb8a6e
Update gradle.properties 2021-03-12 00:11:37 +06:00
25767eecb2 add github badge onto web version 2021-03-02 17:19:17 +06:00
603da9a021 fixes in saves 2021-03-02 16:51:08 +06:00
b43016bb24 repositories properties now checked 2021-03-02 16:45:46 +06:00
4c4845803d
Merge pull request #3 from InsanusMokrassar/rewrite_with_web
add and web target
2021-03-02 14:11:38 +06:00
4ec7d3847f update workflows 2021-03-02 14:02:57 +06:00
2bbfe99ff4 add web publish step 2021-03-02 13:53:12 +06:00
881d268ea9 complete main part 2021-03-02 13:44:33 +06:00
0c8eef971a whole view complete, files handling left 2021-03-02 12:13:05 +06:00
7aa30ef46c temporal state 2021-03-02 02:43:30 +06:00
81 changed files with 2168 additions and 935 deletions

View File

@ -1,4 +1,7 @@
on: [push]
on:
push:
branches:
- master
name: Commit release
@ -16,9 +19,13 @@ jobs:
- name: Set version from gradle.properties
run: echo "version=` cat gradle.properties | grep ^version= | grep -o [\\.0-9]* `" >> $GITHUB_ENV
- name: Build
run: ./gradlew packageUberJarForCurrentOS
env:
additional_version: ""
run: ./gradlew build packageReleaseUberJarForCurrentOS
- name: Publish Web
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./core/build/dist/js/productionExecutable
publish_branch: site
- name: Create Release
id: create_release
uses: actions/create-release@v1
@ -31,12 +38,12 @@ jobs:
draft: false
prerelease: true
- name: Upload Ubuntu Release Asset
id: upload-ubuntu-release-asset
id: upload-ubuntu-release-asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
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
asset_path: "./desktop/build/compose/jars/kmppscriptbuilder.desktop-linux-x64-${{ env.version }}${{ env.additional_version }}.jar"
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: "./core/build/compose/jars/kmppscriptbuilder.core-linux-x64-${{ env.version }}${{ env.additional_version }}.jar"
asset_name: KotlinPublicationScriptsBuilder-linux-x64.jar
asset_content_type: application/java-archive

1
.gitignore vendored
View File

@ -10,3 +10,4 @@ build/
out/
local.properties
kotlin-js-store/

View File

@ -1,6 +1,5 @@
buildscript {
repositories {
jcenter()
google()
mavenCentral()
mavenLocal()
@ -8,21 +7,18 @@ buildscript {
}
dependencies {
classpath 'com.android.tools.build:gradle:4.0.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
classpath "com.getkeepsafe.dexcount:dexcount-gradle-plugin:$dexcount_version"
classpath "org.jetbrains.dokka:dokka-gradle-plugin:$dokka_version"
classpath libs.buildscript.kt.gradle
classpath libs.buildscript.kt.serialization
classpath libs.buildscript.jb.dokka
classpath libs.buildscript.gh.release
}
}
allprojects {
repositories {
mavenLocal()
jcenter()
mavenCentral()
google()
maven { url "https://kotlin.bintray.com/kotlinx" }
maven { url "https://maven.pkg.jetbrains.space/public/p/compose/dev" }
}
}

View File

@ -1,20 +1,46 @@
plugins {
id "org.jetbrains.kotlin.multiplatform"
id "org.jetbrains.kotlin.plugin.serialization"
id "com.android.library"
alias(libs.plugins.jb.compose)
}
apply from: "$mppProjectWithSerializationPresetPath"
kotlin {
js (IR) {
binaries.executable()
}
sourceSets {
commonMain {
dependencies {
api "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version"
api "dev.inmo:micro_utils.coroutines:$micro_utils_version"
api "io.ktor:ktor-client-core:$ktor_version"
api libs.kt.coroutines
api libs.microutils.common
api libs.microutils.coroutines
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"
}
}
}

View File

@ -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)
}
}
"""
}

View File

@ -0,0 +1,67 @@
package dev.inmo.kmppscriptbuilder.core.export.js_only
import dev.inmo.kmppscriptbuilder.core.export.generateMavenConfig
import dev.inmo.kmppscriptbuilder.core.models.*
fun MavenConfig.buildJsOnlyMavenConfig(licenses: List<License>): String = """
apply plugin: 'maven-publish'
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()

View File

@ -1,69 +1,64 @@
package dev.inmo.kmppscriptbuilder.core.export.jvm_only
import dev.inmo.kmppscriptbuilder.core.export.generateMavenConfig
import dev.inmo.kmppscriptbuilder.core.models.*
fun MavenConfig.buildJvmOnlyMavenConfig(licenses: List<License>): String = """
apply plugin: 'maven-publish'
${if (includeGpgSigning) "apply plugin: 'signing'\n" else ""}
task javadocJar(type: Jar) {
from javadoc
classifier = 'javadoc'
}
task sourcesJar(type: Jar) {
from sourceSets.main.allSource
classifier = 'sources'
}
apply plugin: 'maven-publish'
publishing {
publications {
maven(MavenPublication) {
from components.java
artifact javadocJar
artifact sourcesJar
task javadocJar(type: Jar) {
from javadoc
archiveClassifier = 'javadoc'
}
task sourcesJar(type: Jar) {
from sourceSets.main.allSource
archiveClassifier = 'sources'
}
pom {
resolveStrategy = Closure.DELEGATE_FIRST
publishing {
publications {
maven(MavenPublication) {
from components.java
description = "$description"
name = "$name"
url = "$url"
artifact javadocJar
artifact sourcesJar
scm {
developerConnection = "scm:git:[fetch=]${vcsUrl}[push=]${vcsUrl}"
url = "$vcsUrl"
}
pom {
resolveStrategy = Closure.DELEGATE_FIRST
developers {
${developers.joinToString("\n") { """
developer {
id = "${it.id}"
name = "${it.name}"
email = "${it.eMail}"
}
""" }}
}
description = "$description"
name = "$name"
url = "$url"
licenses {
${licenses.joinToString("\n") { """
license {
name = "${it.title}"
url = "${it.url}"
}
""" }}
}
scm {
developerConnection = "scm:git:[fetch=]${vcsUrl}[push=]${vcsUrl}"
url = "$vcsUrl"
}
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 {
useGpgCmd()
sign publishing.publications
}
""" else ""}
""".trimIndent()
}
${gpgSigning.generateMavenConfig()}
""".trimIndent()

View File

@ -1,56 +1,52 @@
package dev.inmo.kmppscriptbuilder.core.export.mpp
import dev.inmo.kmppscriptbuilder.core.export.generateMavenConfig
import dev.inmo.kmppscriptbuilder.core.models.*
fun MavenConfig.buildMultiplatformMavenConfig(licenses: List<License>): String = """
apply plugin: 'maven-publish'
${if (includeGpgSigning) "apply plugin: 'signing'\n" else ""}
task javadocsJar(type: Jar) {
classifier = 'javadoc'
}
apply plugin: 'maven-publish'
publishing {
publications.all {
artifact javadocsJar
task javadocsJar(type: Jar) {
archiveClassifier = 'javadoc'
}
pom {
description = "$description"
name = "$name"
url = "$url"
publishing {
publications.all {
artifact javadocsJar
scm {
developerConnection = "scm:git:[fetch=]${vcsUrl}[push=]${vcsUrl}"
url = "$vcsUrl"
}
pom {
description = "$description"
name = "$name"
url = "$url"
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}"
}
""" }}
}
scm {
developerConnection = "scm:git:[fetch=]${vcsUrl}[push=]${vcsUrl}"
url = "$vcsUrl"
}
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 {
useGpgCmd()
sign publishing.publications
}
""" else ""}
""".trimIndent()
}
${gpgSigning.generateMavenConfig()}
""".trimIndent()

View File

@ -1,5 +1,6 @@
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.mpp.buildMultiplatformMavenConfig
import kotlinx.serialization.*
@ -32,12 +33,6 @@ object ProjectTypeSerializer : KSerializer<ProjectType> {
object MultiplatformProjectType : ProjectType() {
override val name: String = "Multiplatform"
// override fun buildBintrayGradleConfig(
// bintrayConfig: BintrayConfig,
// licenses: List<License>
// ): String = bintrayConfig.buildMultiplatformGradleConfig(
// licenses
// )
override fun buildMavenGradleConfig(
mavenConfig: MavenConfig,
@ -49,12 +44,6 @@ object MultiplatformProjectType : ProjectType() {
object JVMProjectType : ProjectType() {
override val name: String = "JVM"
// override fun buildBintrayGradleConfig(
// bintrayConfig: BintrayConfig,
// licenses: List<License>
// ): String = bintrayConfig.buildJvmOnlyGradleConfig(
// licenses
// )
override fun buildMavenGradleConfig(
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
data class Config(
val licenses: List<License>,

View File

@ -4,6 +4,7 @@ import dev.inmo.kmppscriptbuilder.core.utils.serialFormat
import io.ktor.client.HttpClient
import io.ktor.client.request.get
import io.ktor.client.request.url
import io.ktor.client.statement.bodyAsText
import kotlinx.serialization.Serializable
import kotlinx.serialization.builtins.MapSerializer
import kotlinx.serialization.builtins.serializer
@ -20,9 +21,9 @@ private val commonLicensesListDeserializer = MapSerializer(String.serializer(),
private var licenses: Map<String, License>? = null
suspend fun HttpClient.getLicenses(): Map<String, License> {
val answer = get<String> {
val answer = get {
url("https://licenses.opendefinition.org/licenses/groups/all.json")
}
}.bodyAsText()
return serialFormat.decodeFromString(commonLicensesListDeserializer, answer).also { gotLicenses ->
licenses = gotLicenses
}
@ -30,19 +31,19 @@ suspend fun HttpClient.getLicenses(): Map<String, License> {
suspend fun HttpClient.searchLicense(name: String): List<License> {
val licenses = licenses ?: getLicenses()
val lowerCase = name.toLowerCase()
val upperCase = name.toUpperCase()
val lowerCase = name.lowercase()
val upperCase = name.uppercase()
return licenses.values.filter {
it.title.toLowerCase().contains(lowerCase) || it.title.toUpperCase().contains(upperCase) || it.title.contains(name)
|| it.id.toLowerCase().contains(lowerCase) || it.id.toUpperCase().contains(upperCase) || it.id.contains(name)
it.title.lowercase().contains(lowerCase) || it.title.uppercase().contains(upperCase) || it.title.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> {
val lowerCase = name.toLowerCase()
val upperCase = name.toUpperCase()
val lowerCase = name.lowercase()
val upperCase = name.uppercase()
return values.filter {
it.title.toLowerCase().contains(lowerCase) || it.title.toUpperCase().contains(upperCase) || it.title.contains(name)
|| it.id.toLowerCase().contains(lowerCase) || it.id.toUpperCase().contains(upperCase) || it.id.contains(name)
it.title.lowercase().contains(lowerCase) || it.title.uppercase().contains(upperCase) || it.title.contains(name)
|| it.id.lowercase().contains(lowerCase) || it.id.uppercase().contains(upperCase) || it.id.contains(name)
}
}

View File

@ -2,34 +2,120 @@ package dev.inmo.kmppscriptbuilder.core.models
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
data class MavenConfig(
val name: String,
val description: String,
val url: String,
val vcsUrl: String,
val includeGpgSigning: Boolean = false,
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,
)
@Serializable
data class MavenPublishingRepository(
val name: String,
val url: String
val url: String,
val credsType: CredentialsType = CredentialsType.UsernameAndPassword(
CredentialsType.UsernameAndPassword.defaultUsernameProperty(name),
CredentialsType.UsernameAndPassword.defaultPasswordProperty(name),
)
) {
@Serializable
sealed interface CredentialsType {
@Serializable
object Nothing: CredentialsType {
override fun buildCheckPart(): String = "true"
override fun buildCredsPart(): String = ""
}
@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 {
username = project.hasProperty('${usernameProperty}') ? project.property('${usernameProperty}') : System.getenv('${usernameProperty}')
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.toUpperCase()
name.uppercase()
}
fun build(indent: String) = """maven {
name = "$name"
url = uri("$url")
credentials {
username = project.hasProperty('${nameCapitalized}_USER') ? project.property('${nameCapitalized}_USER') : System.getenv('${nameCapitalized}_USER')
password = project.hasProperty('${nameCapitalized}_PASSWORD') ? project.property('${nameCapitalized}_PASSWORD') : System.getenv('${nameCapitalized}_PASSWORD')
fun build(indent: String): String {
return """if (${credsType.buildCheckPart()}) {
maven {
name = "$name"
url = uri("$url")
${credsType.buildCredsPart()}
}
}""".replace("\n", "\n$indent")
}
}
val SonatypeRepository = MavenPublishingRepository("sonatype", "https://oss.sonatype.org/service/local/staging/deploy/maven2/")

View File

@ -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()
}
}
}

View File

@ -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.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(
id: String = "",
@ -22,10 +27,10 @@ class DevelopersView : ListView<DeveloperState>("Developers info") {
var developers: List<Developer>
get() = itemsList.map { it.toDeveloper() }
set(value) {
itemsList.clear()
itemsList.addAll(
value.map { it.toDeveloperState() }
)
itemsList.apply {
clear()
addAll(value.map { it.toDeveloperState() })
}
}
override val addItemText: String = "Add developer"
@ -34,18 +39,19 @@ class DevelopersView : ListView<DeveloperState>("Developers info") {
override fun createItem(): DeveloperState = DeveloperState()
@Composable
override fun buildView(item: DeveloperState) {
CommonText("Developer username")
CommonTextField(
item.id,
"Developer username"
) { item.id = it }
DefaultSmallVerticalMargin()
CommonText("Developer name")
CommonTextField(
item.name,
"Developer name"
) { item.name = it }
DefaultSmallVerticalMargin()
CommonText("Developer E-Mail")
CommonTextField(
item.eMail,
"Developer E-Mail"
) { item.eMail = it }
}
}

View File

@ -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()
}
}

View File

@ -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()
}
}
}

View File

@ -0,0 +1,106 @@
package dev.inmo.kmppscriptbuilder.core.ui
import androidx.compose.runtime.*
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 val developersView = DevelopersView()
internal val repositoriesView = RepositoriesView()
var mavenConfig: MavenConfig
get() = MavenConfig(
projectNameProperty.ifBlank { defaultProjectName },
projectDescriptionProperty.ifBlank { defaultProjectDescription },
projectUrlProperty,
projectVcsUrlProperty,
developersView.developers,
repositoriesView.repositories + if (publishToMavenCentralProperty) {
listOf(SonatypeRepository)
} else {
emptyList()
},
gpgSignProperty
)
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 }
developersView.developers = value.developers
repositoriesView.repositories = value.repositories.filter { it != SonatypeRepository }
}
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 }
developersView.build()
repositoriesView.build()
}
}

View File

@ -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()
}
}
}
}
}

View File

@ -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)
}
}
}
}
}
}

View File

@ -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)
}
}
}

View File

@ -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()
}

View File

@ -0,0 +1,8 @@
package dev.inmo.kmppscriptbuilder.core.ui.utils
import androidx.compose.runtime.Composable
fun interface Drawer<T> {
@Composable
fun T.draw()
}

View File

@ -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)

View File

@ -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

View File

@ -0,0 +1,3 @@
package dev.inmo.kmppscriptbuilder.core.utils
expect fun openLink(link: String): Boolean

View File

Before

Width:  |  Height:  |  Size: 463 B

After

Width:  |  Height:  |  Size: 463 B

View File

Before

Width:  |  Height:  |  Size: 452 B

After

Width:  |  Height:  |  Size: 452 B

View File

Before

Width:  |  Height:  |  Size: 744 B

After

Width:  |  Height:  |  Size: 744 B

View File

Before

Width:  |  Height:  |  Size: 502 B

After

Width:  |  Height:  |  Size: 502 B

View File

@ -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()
}
})
}

View File

@ -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)

View File

@ -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()
}
}
}

View File

@ -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()) }
}
}
}

View File

@ -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)

View File

@ -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)

View File

@ -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)
)
}
}

View File

@ -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()
}

View File

@ -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()
}
}

View File

@ -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

View File

@ -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
}

View File

@ -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
}

View File

@ -0,0 +1,4 @@
.no-transform {
text-transform: none;
}

File diff suppressed because one or more lines are too long

View 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>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View 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
}
}
}

View File

@ -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()
}

View File

@ -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)

View File

@ -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()
}
}
}
}
}
}

View File

@ -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,)
}
}
}
}

View File

@ -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)

View File

@ -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)

View File

@ -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)
}
}
}
)
}

View File

@ -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()
}
}

View File

@ -1,4 +1,4 @@
package dev.inmo.kmppscriptbuilder.desktop.utils
package dev.inmo.kmppscriptbuilder.core.ui.utils
import java.io.File
import javax.swing.filechooser.FileFilter

View File

@ -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.utils.serialFormat
import dev.inmo.kmppscriptbuilder.core.ui.utils.FileFilter
import dev.inmo.micro_utils.common.MPPFile
import java.io.File
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
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)
fc.addChoosableFileFilter(FileFilter("Kotlin Publication Scripts Builder", Regex(".*\\.$appExtension")))
fc.addChoosableFileFilter(FileFilter("JSON", Regex(".*\\.json")))
return when (fc.showOpenDialog(null)) {
when (fc.showOpenDialog(null)) {
JFileChooser.APPROVE_OPTION -> {
val file = fc.selectedFile
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 {
it.writeText(serialFormat.encodeToString(Config.serializer(), config))
} != null
}
fun exportGradle(config: Config): Boolean {
actual fun exportGradle(config: Config): Boolean {
val fc = JFileChooser(lastFile ?.parent)
fc.fileSelectionMode = JFileChooser.DIRECTORIES_ONLY
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)
fc.addChoosableFileFilter(FileFilter("Kotlin Publication Scripts Builder", Regex(".*\\.$appExtension")))
fc.addChoosableFileFilter(FileFilter("JSON", Regex(".*\\.json")))

View File

@ -0,0 +1,17 @@
package dev.inmo.kmppscriptbuilder.core.utils
import java.awt.Desktop
import java.net.URI
actual fun openLink(link: String): Boolean {
val desktop = if (Desktop.isDesktopSupported()) Desktop.getDesktop() else null
if (desktop != null && desktop.isSupported(Desktop.Action.BROWSE)) {
try {
desktop.browse(URI(link))
return true
} catch (e: Exception) {
e.printStackTrace()
}
}
return false
}

View File

@ -0,0 +1,2 @@
package dev.inmo.kmppscriptbuilder.core.utils

View File

@ -1 +0,0 @@
<manifest package="dev.inmo.KotlinPublicationScriptsBuilder.core"/>

View File

@ -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'
}
}

View File

@ -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"
}
}

View File

@ -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
}
}

View File

@ -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()
}
}

View File

@ -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()
}

View File

@ -1,103 +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.res.svgResource
import androidx.compose.ui.unit.dp
import dev.inmo.kmppscriptbuilder.core.models.Config
import dev.inmo.kmppscriptbuilder.desktop.utils.*
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()
}
}
}
}
}

View File

@ -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")
}
}
}
}
}

View File

@ -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)
}
}
}
}
}

View File

@ -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()
}
}

View File

@ -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())
}
}
}

View File

@ -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 }
}
}

View File

@ -16,7 +16,6 @@ allprojects {
mppProjectWithSerializationPresetPath = "${rootProject.projectDir.absolutePath}/mppProjectWithSerialization.gradle"
mppJavaProjectPresetPath = "${rootProject.projectDir.absolutePath}/mppJavaProject.gradle"
mppJsProjectPresetPath = "${rootProject.projectDir.absolutePath}/mppJsProject.gradle"
mppAndroidProjectPresetPath = "${rootProject.projectDir.absolutePath}/mppAndroidProject.gradle"
defaultAndroidSettingsPresetPath = "${rootProject.projectDir.absolutePath}/defaultAndroidSettings.gradle"

View File

@ -3,30 +3,6 @@ org.gradle.parallel=true
kotlin.js.generate.externals=true
kotlin.incremental=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

45
gradle/libs.versions.toml Normal file
View 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" }

View File

@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
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

View File

@ -1,4 +1,4 @@
project.version = "$version" + System.getenv("additional_version")
project.version = "$version" + (System.getenv("additional_version") != null ? System.getenv("additional_version") : "")
project.group = "$group"
// apply from: "$publishGradlePath"

View File

@ -1,12 +1,10 @@
project.version = "$version" + System.getenv("additional_version")
project.version = "$version" + (System.getenv("additional_version") != null ? System.getenv("additional_version") : "")
project.group = "$group"
// apply from: "$publishGradlePath"
kotlin {
jvm {
compilations.main.kotlinOptions.useIR = true
}
jvm()
sourceSets {
commonMain {

View File

@ -1,4 +1,4 @@
project.version = "$version" + System.getenv("additional_version")
project.version = "$version" + (System.getenv("additional_version") != null ? System.getenv("additional_version") : "")
project.group = "$group"
// apply from: "$publishGradlePath"
@ -6,14 +6,14 @@ project.group = "$group"
kotlin {
js (IR) {
browser()
nodejs()
binaries.executable()
}
sourceSets {
commonMain {
dependencies {
implementation kotlin('stdlib')
api "org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlin_serialisation_core_version"
api libs.kt.serialization
}
}
commonTest {

View File

@ -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"
// apply from: "$publishGradlePath"
kotlin {
jvm {
compilations.main.kotlinOptions.useIR = true
}
jvm()
js (IR) {
browser()
nodejs()
}
android {
publishAllLibraryVariants()
}
sourceSets {
commonMain {
dependencies {
implementation kotlin('stdlib')
api "org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlin_serialisation_core_version"
api libs.kt.serialization
}
}
commonTest {
@ -39,14 +34,5 @@ kotlin {
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"

View File

@ -9,8 +9,8 @@ rootProject.name = 'kmppscriptbuilder'
String[] includes = [
":core",
":desktop",
":web"
// ":desktop",
// ":web"
]

View File

@ -1,6 +0,0 @@
plugins {
id "org.jetbrains.kotlin.multiplatform"
id "org.jetbrains.kotlin.plugin.serialization"
}
apply from: "$mppJsProjectPresetPath"

View File

@ -1,83 +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>
<div uk-sticky="sel-target: .uk-navbar-container; cls-active: uk-navbar-sticky; bottom: #transparent-sticky-navbar">
<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>
<div class="uk-navbar-right">
<ul class="uk-navbar-nav">
<li uk-tooltip="title: Open file"><a href="#"><span uk-icon="icon: pull"></span></a></li><!--Open file-->
<li uk-tooltip="title: Save file"><a href="#"><span uk-icon="icon: push"></span></a></li><!--Save file-->
</ul>
</div>
</nav>
</div>
<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 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 class="uk-padding-small">
<button class="uk-button uk-button-primary">Add developer</button>
</div>
<legend class="uk-legend">Repositories info</legend>
<div class="uk-padding-small">
<button class="uk-button uk-button-primary">Add repository</button>
</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>
</body>
</html>