Compare commits
	
		
			14 Commits
		
	
	
		
			build-ca1a
			...
			build-6b5a
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 6b5ab5acba | |||
| f723d55d7e | |||
| c0d0b7521e | |||
| 7536c67589 | |||
| 0770772e7d | |||
| c6b1289f5a | |||
| 788fe49aa4 | |||
| 3be0f24eac | |||
| 9fe7c458e9 | |||
| 8430e68167 | |||
| 53a76c7a73 | |||
| 70baa30127 | |||
| 283bc5acb4 | |||
| 26a5d20e26 | 
							
								
								
									
										4
									
								
								.github/workflows/commit-release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						@@ -19,7 +19,7 @@ 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 build packageUberJarForCurrentOS
 | 
			
		||||
        run: ./gradlew build packageReleaseUberJarForCurrentOS
 | 
			
		||||
      - name: Publish Web
 | 
			
		||||
        uses: peaceiris/actions-gh-pages@v3
 | 
			
		||||
        with:
 | 
			
		||||
@@ -44,6 +44,6 @@ jobs:
 | 
			
		||||
          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"
 | 
			
		||||
          asset_path: "core/build/compose/jars/*.jar"
 | 
			
		||||
          asset_name: KotlinPublicationScriptsBuilder-linux-x64.jar
 | 
			
		||||
          asset_content_type: application/java-archive
 | 
			
		||||
 
 | 
			
		||||
@@ -7,11 +7,10 @@ buildscript {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    dependencies {
 | 
			
		||||
        classpath 'com.android.tools.build:gradle:7.0.4'
 | 
			
		||||
        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
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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"
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,14 @@ if (project.hasProperty("signing.gnupg.keyName")) {
 | 
			
		||||
    
 | 
			
		||||
        sign publishing.publications
 | 
			
		||||
    }
 | 
			
		||||
}"""
 | 
			
		||||
    
 | 
			
		||||
    task signAll {
 | 
			
		||||
        tasks.withType(Sign).forEach {
 | 
			
		||||
            dependsOn(it)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
"""
 | 
			
		||||
    GpgSigning.Enabled ->
 | 
			
		||||
"""
 | 
			
		||||
apply plugin: 'signing'
 | 
			
		||||
@@ -23,5 +30,12 @@ signing {
 | 
			
		||||
    useGpgCmd()
 | 
			
		||||
 | 
			
		||||
    sign publishing.publications
 | 
			
		||||
}"""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
task signAll {
 | 
			
		||||
    tasks.withType(Sign).forEach {
 | 
			
		||||
        dependsOn(it)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
"""
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -31,23 +31,84 @@ data class MavenConfig(
 | 
			
		||||
@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),
 | 
			
		||||
    )
 | 
			
		||||
) {
 | 
			
		||||
    private val nameCapitalized by lazy {
 | 
			
		||||
        name.toUpperCase()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun build(indent: String): String {
 | 
			
		||||
        val usernameProperty = "${nameCapitalized}_USER"
 | 
			
		||||
        val passwordProperty = "${nameCapitalized}_PASSWORD"
 | 
			
		||||
        return """if ((project.hasProperty('${usernameProperty}') || System.getenv('${usernameProperty}') != null) && (project.hasProperty('${passwordProperty}') || System.getenv('${passwordProperty}') != null)) {
 | 
			
		||||
    maven {
 | 
			
		||||
        name = "$name"
 | 
			
		||||
        url = uri("$url")
 | 
			
		||||
    @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}')
 | 
			
		||||
        }
 | 
			
		||||
"""
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            companion object {
 | 
			
		||||
                fun defaultValueProperty(name: String): String {
 | 
			
		||||
                    return "${name.uppercase()}_TOKEN"
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fun buildCheckPart(): String
 | 
			
		||||
        fun buildCredsPart(): String
 | 
			
		||||
    }
 | 
			
		||||
    private val nameCapitalized by lazy {
 | 
			
		||||
        name.uppercase()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun build(indent: String): String {
 | 
			
		||||
        return """if (${credsType.buildCheckPart()}) {
 | 
			
		||||
    maven {
 | 
			
		||||
        name = "$name"
 | 
			
		||||
        url = uri("$url")
 | 
			
		||||
${credsType.buildCredsPart()}
 | 
			
		||||
    }
 | 
			
		||||
}""".replace("\n", "\n$indent")
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,56 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.core.ui
 | 
			
		||||
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.runtime.getValue
 | 
			
		||||
import androidx.compose.runtime.mutableStateOf
 | 
			
		||||
import androidx.compose.runtime.setValue
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.models.Config
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.DefaultContentColumn
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.DefaultDivider
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
expect fun TopAppBar(
 | 
			
		||||
    config: Config,
 | 
			
		||||
    saveAvailable: Boolean,
 | 
			
		||||
    onSaveAvailable: (Boolean) -> Unit,
 | 
			
		||||
    onNewConfig: (Config) -> Unit
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
class BuilderView : View() {
 | 
			
		||||
    internal val projectTypeView by mutableStateOf(ProjectTypeView())
 | 
			
		||||
    internal val mavenInfoView by mutableStateOf(MavenInfoView())
 | 
			
		||||
    internal val licensesView by mutableStateOf(LicensesView())
 | 
			
		||||
 | 
			
		||||
    internal var saveAvailableState by mutableStateOf(false)
 | 
			
		||||
    var config: Config
 | 
			
		||||
        get() {
 | 
			
		||||
            return Config(licensesView.licenses, mavenInfoView.mavenConfig, projectTypeView.projectType)
 | 
			
		||||
        }
 | 
			
		||||
        set(value) {
 | 
			
		||||
            licensesView.licenses = value.licenses
 | 
			
		||||
            mavenInfoView.mavenConfig = value.mavenConfig
 | 
			
		||||
            projectTypeView.projectType = value.type
 | 
			
		||||
            saveAvailableState = true
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    @Composable
 | 
			
		||||
    override fun build() {
 | 
			
		||||
        TopAppBar(
 | 
			
		||||
            config,
 | 
			
		||||
            saveAvailableState,
 | 
			
		||||
            {
 | 
			
		||||
                saveAvailableState = it
 | 
			
		||||
            }
 | 
			
		||||
        ) {
 | 
			
		||||
            config = it
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        DefaultContentColumn {
 | 
			
		||||
            projectTypeView.build()
 | 
			
		||||
            DefaultDivider()
 | 
			
		||||
            licensesView.build()
 | 
			
		||||
            DefaultDivider()
 | 
			
		||||
            mavenInfoView.build()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,8 +1,13 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.desktop.views
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.core.ui
 | 
			
		||||
 | 
			
		||||
import androidx.compose.runtime.*
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.runtime.getValue
 | 
			
		||||
import androidx.compose.runtime.mutableStateOf
 | 
			
		||||
import androidx.compose.runtime.setValue
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.models.Developer
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.desktop.utils.CommonTextField
 | 
			
		||||
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 }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,103 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.core.ui
 | 
			
		||||
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.runtime.derivedStateOf
 | 
			
		||||
import androidx.compose.runtime.getValue
 | 
			
		||||
import androidx.compose.runtime.mutableStateListOf
 | 
			
		||||
import androidx.compose.runtime.mutableStateOf
 | 
			
		||||
import androidx.compose.runtime.setValue
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.models.License
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.models.getLicenses
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.CommonText
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.CommonTextField
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.DefaultSmallVerticalMargin
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.Drawer
 | 
			
		||||
import io.ktor.client.HttpClient
 | 
			
		||||
import kotlinx.coroutines.CoroutineScope
 | 
			
		||||
import kotlinx.coroutines.Dispatchers
 | 
			
		||||
import kotlinx.coroutines.launch
 | 
			
		||||
 | 
			
		||||
class LicenseState(
 | 
			
		||||
    id: String = "",
 | 
			
		||||
    title: String = "",
 | 
			
		||||
    url: String? = null
 | 
			
		||||
) {
 | 
			
		||||
    var id: String by mutableStateOf(id)
 | 
			
		||||
    var title: String by mutableStateOf(title)
 | 
			
		||||
    var url: String? by mutableStateOf(url)
 | 
			
		||||
 | 
			
		||||
    fun toLicense() = License(id, title, url)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
internal fun License.toLicenseState() = LicenseState(id, title, url)
 | 
			
		||||
 | 
			
		||||
expect object LicensesDrawer : Drawer<LicensesView>
 | 
			
		||||
 | 
			
		||||
class LicensesView : ListView<LicenseState>("Licenses") {
 | 
			
		||||
    var licenses: List<License>
 | 
			
		||||
        get() = itemsList.map { it.toLicense() }
 | 
			
		||||
        set(value) {
 | 
			
		||||
            itemsList.clear()
 | 
			
		||||
            itemsList.addAll(value.map { it.toLicenseState() })
 | 
			
		||||
        }
 | 
			
		||||
    internal val availableLicensesState = mutableStateListOf<License>()
 | 
			
		||||
    internal var licenseSearchFilter by mutableStateOf("")
 | 
			
		||||
    internal val searchFieldFocused = mutableStateOf(false)
 | 
			
		||||
    internal val licensesOffersToShow = derivedStateOf {
 | 
			
		||||
        val query = licenseSearchFilter.lowercase()
 | 
			
		||||
        availableLicensesState.filter {
 | 
			
		||||
            it.title.lowercase().contains(query)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override val addItemText: String
 | 
			
		||||
        get() = "Add empty license"
 | 
			
		||||
 | 
			
		||||
    init {
 | 
			
		||||
        CoroutineScope(Dispatchers.Default).launch {
 | 
			
		||||
            val client = HttpClient()
 | 
			
		||||
            availableLicensesState.addAll(client.getLicenses().values)
 | 
			
		||||
            client.close()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun createItem(): LicenseState = LicenseState()
 | 
			
		||||
 | 
			
		||||
    @Composable
 | 
			
		||||
    override fun buildView(item: LicenseState) {
 | 
			
		||||
        CommonText("License ID")
 | 
			
		||||
        CommonTextField(
 | 
			
		||||
            item.id,
 | 
			
		||||
            "Short name like \"Apache-2.0\"",
 | 
			
		||||
        ) { item.id = it }
 | 
			
		||||
        CommonText("License title")
 | 
			
		||||
        CommonTextField(
 | 
			
		||||
            item.title,
 | 
			
		||||
            "Official title of license (like \"Apache Software License 2.0\")",
 | 
			
		||||
        ) { item.title = it }
 | 
			
		||||
        CommonText("License URL")
 | 
			
		||||
        CommonTextField(
 | 
			
		||||
            item.url ?: "",
 | 
			
		||||
            "Link to your LICENSE file OR official license file (like \"https://opensource.org/licenses/Apache-2.0\")",
 | 
			
		||||
        ) { item.url = it }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override val content: @Composable () -> Unit = {
 | 
			
		||||
        CommonTextField(
 | 
			
		||||
            licenseSearchFilter,
 | 
			
		||||
            "Search filter",
 | 
			
		||||
            onFocusChanged = {
 | 
			
		||||
                searchFieldFocused.value = it
 | 
			
		||||
            }
 | 
			
		||||
        ) { filterText ->
 | 
			
		||||
            licenseSearchFilter = filterText
 | 
			
		||||
        }
 | 
			
		||||
        DefaultSmallVerticalMargin()
 | 
			
		||||
 | 
			
		||||
        with(LicensesDrawer) { draw() }
 | 
			
		||||
 | 
			
		||||
        DefaultSmallVerticalMargin()
 | 
			
		||||
 | 
			
		||||
        super.content()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,26 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.core.ui
 | 
			
		||||
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.runtime.mutableStateListOf
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.Drawer
 | 
			
		||||
 | 
			
		||||
expect class ListViewDrawer<T>() : Drawer<ListView<T>>
 | 
			
		||||
 | 
			
		||||
abstract class ListView<T>(title: String) : VerticalView(title) {
 | 
			
		||||
    internal val itemsList = mutableStateListOf<T>()
 | 
			
		||||
 | 
			
		||||
    internal open val addItemText: String = "Add"
 | 
			
		||||
    internal open val removeItemText: String = "Remove"
 | 
			
		||||
 | 
			
		||||
    internal abstract fun createItem(): T
 | 
			
		||||
    @Composable
 | 
			
		||||
    internal abstract fun buildView(item: T)
 | 
			
		||||
 | 
			
		||||
    protected val drawer = ListViewDrawer<T>()
 | 
			
		||||
 | 
			
		||||
    override val content: @Composable () -> Unit = {
 | 
			
		||||
        with(drawer) {
 | 
			
		||||
            draw()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,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()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,36 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.core.ui
 | 
			
		||||
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.runtime.getValue
 | 
			
		||||
import androidx.compose.runtime.mutableStateOf
 | 
			
		||||
import androidx.compose.runtime.setValue
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.models.JSProjectType
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.models.JVMProjectType
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.models.MultiplatformProjectType
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.models.ProjectType
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.ButtonsPanel
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.DefaultSmallVerticalMargin
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.Drawer
 | 
			
		||||
 | 
			
		||||
expect class ProjectTypeDrawer : Drawer<ProjectType>
 | 
			
		||||
expect fun ProjectTypeDrawerWithView(view: ProjectTypeView): ProjectTypeDrawer
 | 
			
		||||
 | 
			
		||||
class ProjectTypeView : VerticalView("Project type") {
 | 
			
		||||
    var projectType by mutableStateOf<ProjectType>(MultiplatformProjectType)
 | 
			
		||||
    private val typeDrawer = ProjectTypeDrawerWithView(this)
 | 
			
		||||
 | 
			
		||||
    override val content: @Composable () -> Unit = {
 | 
			
		||||
        ButtonsPanel(
 | 
			
		||||
            "Project type",
 | 
			
		||||
            MultiplatformProjectType,
 | 
			
		||||
            JVMProjectType,
 | 
			
		||||
            JSProjectType
 | 
			
		||||
        ) {
 | 
			
		||||
            with(typeDrawer) {
 | 
			
		||||
                with (it) {
 | 
			
		||||
                    draw()
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,142 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.core.ui
 | 
			
		||||
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.runtime.getValue
 | 
			
		||||
import androidx.compose.runtime.mutableStateOf
 | 
			
		||||
import androidx.compose.runtime.remember
 | 
			
		||||
import androidx.compose.runtime.setValue
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.models.MavenPublishingRepository
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.ButtonsPanel
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.CommonText
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.CommonTextField
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.DefaultContentColumn
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.DefaultSmallVerticalMargin
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.Drawer
 | 
			
		||||
 | 
			
		||||
class RepositoryState(
 | 
			
		||||
    name: String = "",
 | 
			
		||||
    url: String = "",
 | 
			
		||||
    credsType: MavenPublishingRepository.CredentialsType = MavenPublishingRepository.CredentialsType.UsernameAndPassword(name)
 | 
			
		||||
) {
 | 
			
		||||
    var name: String by mutableStateOf(name)
 | 
			
		||||
    var url: String by mutableStateOf(url)
 | 
			
		||||
    var credsType by mutableStateOf(credsType)
 | 
			
		||||
 | 
			
		||||
    fun toRepository() = MavenPublishingRepository(name, url, credsType)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
private fun MavenPublishingRepository.toRepositoryState() = RepositoryState(name, url, credsType)
 | 
			
		||||
 | 
			
		||||
expect class RepositoryCredentialTypeDrawer : Drawer<MavenPublishingRepository.CredentialsType>
 | 
			
		||||
expect fun RepositoryCredentialTypeDrawerWithState(repositoryState: RepositoryState): RepositoryCredentialTypeDrawer
 | 
			
		||||
 | 
			
		||||
class RepositoriesView : ListView<RepositoryState>("Repositories info") {
 | 
			
		||||
    var repositories: List<MavenPublishingRepository>
 | 
			
		||||
        get() = itemsList.map { it.toRepository() }
 | 
			
		||||
        set(value) {
 | 
			
		||||
            itemsList.clear()
 | 
			
		||||
            itemsList.addAll(
 | 
			
		||||
                value.map { it.toRepositoryState() }
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    override val addItemText: String = "Add repository"
 | 
			
		||||
    override val removeItemText: String = "Remove repository"
 | 
			
		||||
 | 
			
		||||
    override fun createItem(): RepositoryState = RepositoryState()
 | 
			
		||||
 | 
			
		||||
    @Composable
 | 
			
		||||
    override fun buildView(item: RepositoryState) {
 | 
			
		||||
        val credsTypesDrawer = remember {
 | 
			
		||||
            RepositoryCredentialTypeDrawerWithState(item)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        CommonText("Repository name")
 | 
			
		||||
        CommonTextField(
 | 
			
		||||
            item.name,
 | 
			
		||||
            "This name will be used to identify repository in gradle"
 | 
			
		||||
        ) {
 | 
			
		||||
            val previous = item.name
 | 
			
		||||
            item.name = it
 | 
			
		||||
            when (val currentCredsType = item.credsType) {
 | 
			
		||||
                is MavenPublishingRepository.CredentialsType.HttpHeaderCredentials -> {
 | 
			
		||||
                    if (MavenPublishingRepository.CredentialsType.HttpHeaderCredentials.defaultValueProperty(previous) == currentCredsType.headerValueProperty) {
 | 
			
		||||
                        item.credsType = currentCredsType.copy(
 | 
			
		||||
                            headerValueProperty = MavenPublishingRepository.CredentialsType.HttpHeaderCredentials.defaultValueProperty(it)
 | 
			
		||||
                        )
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                MavenPublishingRepository.CredentialsType.Nothing -> {}
 | 
			
		||||
                is MavenPublishingRepository.CredentialsType.UsernameAndPassword -> {
 | 
			
		||||
                    var current: MavenPublishingRepository.CredentialsType.UsernameAndPassword = currentCredsType
 | 
			
		||||
                    if (MavenPublishingRepository.CredentialsType.UsernameAndPassword.defaultUsernameProperty(previous) == currentCredsType.usernameProperty) {
 | 
			
		||||
                        current = current.copy(
 | 
			
		||||
                            usernameProperty = MavenPublishingRepository.CredentialsType.UsernameAndPassword.defaultUsernameProperty(it)
 | 
			
		||||
                        )
 | 
			
		||||
                    }
 | 
			
		||||
                    if (MavenPublishingRepository.CredentialsType.UsernameAndPassword.defaultPasswordProperty(previous) == currentCredsType.passwordProperty) {
 | 
			
		||||
                        current = current.copy(
 | 
			
		||||
                            passwordProperty = MavenPublishingRepository.CredentialsType.UsernameAndPassword.defaultPasswordProperty(it)
 | 
			
		||||
                        )
 | 
			
		||||
                    }
 | 
			
		||||
                    item.credsType = current
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        DefaultSmallVerticalMargin()
 | 
			
		||||
        CommonText("Repository url")
 | 
			
		||||
        CommonTextField(
 | 
			
		||||
            item.url,
 | 
			
		||||
            "For example: https://repo.maven.apache.org/maven2/"
 | 
			
		||||
        ) { item.url = it }
 | 
			
		||||
 | 
			
		||||
        ButtonsPanel(
 | 
			
		||||
            "Credentials type",
 | 
			
		||||
            MavenPublishingRepository.CredentialsType.Nothing.takeIf { item.credsType != it } ?: item.credsType,
 | 
			
		||||
            MavenPublishingRepository.CredentialsType.UsernameAndPassword(item.name).takeIf { item.credsType !is MavenPublishingRepository.CredentialsType.UsernameAndPassword } ?: item.credsType,
 | 
			
		||||
            MavenPublishingRepository.CredentialsType.HttpHeaderCredentials(
 | 
			
		||||
                "Authorization",
 | 
			
		||||
                MavenPublishingRepository.CredentialsType.HttpHeaderCredentials.defaultValueProperty(item.name)
 | 
			
		||||
            ).takeIf { item.credsType !is MavenPublishingRepository.CredentialsType.HttpHeaderCredentials } ?: item.credsType,
 | 
			
		||||
        ) {
 | 
			
		||||
            with(credsTypesDrawer) {
 | 
			
		||||
                with(it) {
 | 
			
		||||
                    draw()
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        DefaultContentColumn {
 | 
			
		||||
            when (val credsType = item.credsType) {
 | 
			
		||||
                is MavenPublishingRepository.CredentialsType.HttpHeaderCredentials -> {
 | 
			
		||||
                    CommonText("Header name")
 | 
			
		||||
                    CommonTextField(credsType.headerName) {
 | 
			
		||||
                        item.credsType = credsType.copy(headerName = it)
 | 
			
		||||
                    }
 | 
			
		||||
                    DefaultSmallVerticalMargin()
 | 
			
		||||
 | 
			
		||||
                    CommonText("Property name")
 | 
			
		||||
                    CommonTextField(credsType.headerValueProperty) {
 | 
			
		||||
                        item.credsType = credsType.copy(headerValueProperty = it)
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                MavenPublishingRepository.CredentialsType.Nothing -> {
 | 
			
		||||
                    CommonText("No parameters for absence of credentials")
 | 
			
		||||
                }
 | 
			
		||||
                is MavenPublishingRepository.CredentialsType.UsernameAndPassword -> {
 | 
			
		||||
                    CommonText("Username property name")
 | 
			
		||||
                    CommonTextField(credsType.usernameProperty) {
 | 
			
		||||
                        item.credsType = credsType.copy(usernameProperty = it)
 | 
			
		||||
                    }
 | 
			
		||||
                    DefaultSmallVerticalMargin()
 | 
			
		||||
 | 
			
		||||
                    CommonText("Password property name")
 | 
			
		||||
                    CommonTextField(credsType.passwordProperty) {
 | 
			
		||||
                        item.credsType = credsType.copy(passwordProperty = it)
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,14 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.core.ui
 | 
			
		||||
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.DefaultContentColumn
 | 
			
		||||
 | 
			
		||||
abstract class VerticalView(protected val title: String) : View() {
 | 
			
		||||
    abstract val content: @Composable () -> Unit
 | 
			
		||||
    @Composable
 | 
			
		||||
    override fun build() {
 | 
			
		||||
        DefaultContentColumn {
 | 
			
		||||
            DrawVertically(title, content)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,16 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.core.ui
 | 
			
		||||
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
 | 
			
		||||
expect abstract class View() {
 | 
			
		||||
    @Composable
 | 
			
		||||
    abstract fun build()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
expect fun View.DrawVertically(title: String, block: @Composable () -> Unit)
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
fun <T : View> T.init(): T = apply {
 | 
			
		||||
    build()
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,8 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.core.ui.utils
 | 
			
		||||
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
 | 
			
		||||
fun interface Drawer<T> {
 | 
			
		||||
    @Composable
 | 
			
		||||
    fun T.draw()
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,49 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.core.ui.utils
 | 
			
		||||
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
expect fun TitleText(text: String)
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
expect fun CommonText(text: String, onClick: (() -> Unit)? = null)
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
expect fun CommonTextField(
 | 
			
		||||
    presetText: String,
 | 
			
		||||
    hint: String? = null,
 | 
			
		||||
    onFocusChanged: (Boolean) -> Unit = {},
 | 
			
		||||
    onChange: (String) -> Unit
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
expect fun SwitchWithLabel(
 | 
			
		||||
    label: String,
 | 
			
		||||
    checked: Boolean,
 | 
			
		||||
    placeSwitchAtTheStart: Boolean = false,
 | 
			
		||||
    switchEnabled: Boolean = true,
 | 
			
		||||
    onCheckedChange: (Boolean) -> Unit
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
expect fun <T> ButtonsPanel(
 | 
			
		||||
    title: String,
 | 
			
		||||
    data: Iterable<T>,
 | 
			
		||||
    itemDrawer: @Composable (T) -> Unit
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
fun <T> ButtonsPanel(
 | 
			
		||||
    title: String,
 | 
			
		||||
    vararg data: T,
 | 
			
		||||
    itemDrawer: @Composable (T) -> Unit
 | 
			
		||||
) = ButtonsPanel(title, data.toList(), itemDrawer)
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
expect fun DefaultDivider()
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
expect fun DefaultSmallVerticalMargin()
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
expect fun DefaultContentColumn(block: @Composable () -> Unit)
 | 
			
		||||
@@ -0,0 +1,14 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.core.utils
 | 
			
		||||
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.models.Config
 | 
			
		||||
import dev.inmo.micro_utils.common.MPPFile
 | 
			
		||||
 | 
			
		||||
internal const val appExtension = "kpsb"
 | 
			
		||||
 | 
			
		||||
expect fun openNewConfig(onParsed: (Config) -> Unit)
 | 
			
		||||
 | 
			
		||||
expect fun saveConfig(config: Config): Boolean
 | 
			
		||||
 | 
			
		||||
expect fun exportGradle(config: Config): Boolean
 | 
			
		||||
 | 
			
		||||
expect fun saveAs(config: Config): Boolean
 | 
			
		||||
@@ -0,0 +1,3 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.core.utils
 | 
			
		||||
 | 
			
		||||
expect fun openLink(link: String): Boolean
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 463 B After Width: | Height: | Size: 463 B  | 
| 
		 Before Width: | Height: | Size: 452 B After Width: | Height: | Size: 452 B  | 
| 
		 Before Width: | Height: | Size: 744 B After Width: | Height: | Size: 744 B  | 
| 
		 Before Width: | Height: | Size: 502 B After Width: | Height: | Size: 502 B  | 
@@ -0,0 +1,14 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.core
 | 
			
		||||
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.ui.BuilderView
 | 
			
		||||
import kotlinx.browser.window
 | 
			
		||||
import org.jetbrains.compose.web.renderComposableInBody
 | 
			
		||||
 | 
			
		||||
fun main() {
 | 
			
		||||
    window.addEventListener("load", {
 | 
			
		||||
        val builder = BuilderView()
 | 
			
		||||
        renderComposableInBody {
 | 
			
		||||
            builder.build()
 | 
			
		||||
        }
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,35 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.core.ui
 | 
			
		||||
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import dev.inmo.jsuikit.elements.DefaultButton
 | 
			
		||||
import dev.inmo.jsuikit.modifiers.UIKitButton
 | 
			
		||||
import dev.inmo.jsuikit.modifiers.UIKitMargin
 | 
			
		||||
import dev.inmo.jsuikit.modifiers.UIKitTooltipModifier
 | 
			
		||||
import dev.inmo.jsuikit.modifiers.UIKitUtility
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.models.GpgSigning
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.Drawer
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.NoTransform
 | 
			
		||||
 | 
			
		||||
actual class GpgSigningOptionDrawer(
 | 
			
		||||
    private val mavenInfoView: MavenInfoView
 | 
			
		||||
) : Drawer<GpgSigning> {
 | 
			
		||||
    @Composable
 | 
			
		||||
    override fun GpgSigning.draw() {
 | 
			
		||||
        val tooltipModifier = UIKitTooltipModifier(
 | 
			
		||||
            when (this) {
 | 
			
		||||
                GpgSigning.Disabled -> "Signing will not be added"
 | 
			
		||||
                GpgSigning.Enabled -> "Signing will be always enabled"
 | 
			
		||||
                GpgSigning.Optional -> "Signing will be added, but disabled in case of absence 'signatory.keyId'"
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
        if (mavenInfoView.gpgSignProperty == this) {
 | 
			
		||||
            DefaultButton(name, UIKitButton.Type.Primary, UIKitButton.Size.Small, UIKitMargin.Small.Horizontal, UIKitUtility.NoTransform, UIKitUtility.Border.Rounded, tooltipModifier)
 | 
			
		||||
        } else {
 | 
			
		||||
            DefaultButton(name, UIKitButton.Type.Default, UIKitButton.Size.Small, UIKitMargin.Small.Horizontal, UIKitUtility.NoTransform, UIKitUtility.Border.Rounded, tooltipModifier) {
 | 
			
		||||
                mavenInfoView.gpgSignProperty = this
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
actual fun GpgSigningOptionDrawerWithView(view: MavenInfoView): GpgSigningOptionDrawer = GpgSigningOptionDrawer(mavenInfoView = view)
 | 
			
		||||
@@ -0,0 +1,37 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.core.ui
 | 
			
		||||
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import dev.inmo.jsuikit.elements.DefaultButton
 | 
			
		||||
import dev.inmo.jsuikit.elements.Divider
 | 
			
		||||
import dev.inmo.jsuikit.modifiers.UIKitButton
 | 
			
		||||
import dev.inmo.jsuikit.modifiers.UIKitMargin
 | 
			
		||||
import dev.inmo.jsuikit.modifiers.UIKitUtility
 | 
			
		||||
import dev.inmo.jsuikit.modifiers.builder
 | 
			
		||||
import dev.inmo.jsuikit.utils.Attrs
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.CommonTextField
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.Drawer
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.NoTransform
 | 
			
		||||
import org.jetbrains.compose.web.dom.Div
 | 
			
		||||
 | 
			
		||||
actual object LicensesDrawer : Drawer<LicensesView> {
 | 
			
		||||
    @Composable
 | 
			
		||||
    override fun LicensesView.draw() {
 | 
			
		||||
        dev.inmo.jsuikit.elements.List(
 | 
			
		||||
            licensesOffersToShow.value,
 | 
			
		||||
            Attrs {
 | 
			
		||||
                if (!searchFieldFocused.value) {
 | 
			
		||||
                    hidden()
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        ) {
 | 
			
		||||
            DefaultButton(
 | 
			
		||||
                it.title,
 | 
			
		||||
                UIKitButton.Type.Text
 | 
			
		||||
            ) { _ ->
 | 
			
		||||
                itemsList.add(it.toLicenseState())
 | 
			
		||||
                licenseSearchFilter = ""
 | 
			
		||||
            }
 | 
			
		||||
            Divider.Common()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,28 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.core.ui
 | 
			
		||||
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import dev.inmo.jsuikit.elements.DefaultButton
 | 
			
		||||
import dev.inmo.jsuikit.modifiers.UIKitButton
 | 
			
		||||
import dev.inmo.jsuikit.modifiers.UIKitMargin
 | 
			
		||||
import dev.inmo.jsuikit.modifiers.UIKitUtility
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.DefaultContentColumn
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.Drawer
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.NoTransform
 | 
			
		||||
 | 
			
		||||
actual class ListViewDrawer<T> : Drawer<ListView<T>> {
 | 
			
		||||
    @Composable
 | 
			
		||||
    override fun ListView<T>.draw() {
 | 
			
		||||
        itemsList.forEach { item ->
 | 
			
		||||
            DefaultContentColumn {
 | 
			
		||||
                buildView(item)
 | 
			
		||||
                DefaultButton(removeItemText, UIKitButton.Type.Default, UIKitMargin.Small, UIKitUtility.NoTransform, UIKitUtility.Border.Rounded) {
 | 
			
		||||
                    itemsList.remove(item)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            DefaultButton(addItemText, UIKitButton.Type.Primary, UIKitUtility.NoTransform, UIKitUtility.Border.Rounded ) { itemsList.add(createItem()) }
 | 
			
		||||
        }
 | 
			
		||||
        if (itemsList.isEmpty()) {
 | 
			
		||||
            DefaultButton(addItemText, UIKitButton.Type.Primary, UIKitUtility.NoTransform, UIKitUtility.Border.Rounded ) { itemsList.add(createItem()) }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,28 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.core.ui
 | 
			
		||||
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import dev.inmo.jsuikit.elements.DefaultButton
 | 
			
		||||
import dev.inmo.jsuikit.modifiers.UIKitButton
 | 
			
		||||
import dev.inmo.jsuikit.modifiers.UIKitMargin
 | 
			
		||||
import dev.inmo.jsuikit.modifiers.UIKitText
 | 
			
		||||
import dev.inmo.jsuikit.modifiers.UIKitUtility
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.models.ProjectType
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.Drawer
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.NoTransform
 | 
			
		||||
 | 
			
		||||
actual class ProjectTypeDrawer(
 | 
			
		||||
    private val projectTypeView: ProjectTypeView
 | 
			
		||||
) : Drawer<ProjectType> {
 | 
			
		||||
    @Composable
 | 
			
		||||
    override fun ProjectType.draw() {
 | 
			
		||||
        if (projectTypeView.projectType == this) {
 | 
			
		||||
            DefaultButton(name, UIKitButton.Type.Primary, UIKitButton.Size.Small, UIKitMargin.Small.Horizontal, UIKitUtility.NoTransform, UIKitUtility.Border.Rounded)
 | 
			
		||||
        } else {
 | 
			
		||||
            DefaultButton(name, UIKitButton.Type.Default, UIKitButton.Size.Small, UIKitMargin.Small.Horizontal, UIKitUtility.NoTransform, UIKitUtility.Border.Rounded) {
 | 
			
		||||
                projectTypeView.projectType = this
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
actual fun ProjectTypeDrawerWithView(view: ProjectTypeView): ProjectTypeDrawer = ProjectTypeDrawer(projectTypeView = view)
 | 
			
		||||
@@ -0,0 +1,32 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.core.ui
 | 
			
		||||
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import dev.inmo.jsuikit.elements.DefaultButton
 | 
			
		||||
import dev.inmo.jsuikit.modifiers.UIKitButton
 | 
			
		||||
import dev.inmo.jsuikit.modifiers.UIKitMargin
 | 
			
		||||
import dev.inmo.jsuikit.modifiers.UIKitUtility
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.models.MavenPublishingRepository
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.Drawer
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.NoTransform
 | 
			
		||||
 | 
			
		||||
actual class RepositoryCredentialTypeDrawer(
 | 
			
		||||
    private val state: RepositoryState
 | 
			
		||||
) : Drawer<MavenPublishingRepository.CredentialsType> {
 | 
			
		||||
    @Composable
 | 
			
		||||
    override fun MavenPublishingRepository.CredentialsType.draw() {
 | 
			
		||||
        val name = when (this@draw) {
 | 
			
		||||
            is MavenPublishingRepository.CredentialsType.HttpHeaderCredentials -> "Headers"
 | 
			
		||||
            MavenPublishingRepository.CredentialsType.Nothing -> "No"
 | 
			
		||||
            is MavenPublishingRepository.CredentialsType.UsernameAndPassword -> "Username and password"
 | 
			
		||||
        }
 | 
			
		||||
        if (state.credsType == this) {
 | 
			
		||||
            DefaultButton(name, UIKitButton.Type.Primary, UIKitButton.Size.Small, UIKitMargin.Small.Horizontal, UIKitUtility.NoTransform, UIKitUtility.Border.Rounded)
 | 
			
		||||
        } else {
 | 
			
		||||
            DefaultButton(name, UIKitButton.Type.Default, UIKitButton.Size.Small, UIKitMargin.Small.Horizontal, UIKitUtility.NoTransform, UIKitUtility.Border.Rounded) {
 | 
			
		||||
                state.credsType = this
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
actual fun RepositoryCredentialTypeDrawerWithState(repositoryState: RepositoryState): RepositoryCredentialTypeDrawer = RepositoryCredentialTypeDrawer(repositoryState)
 | 
			
		||||
@@ -0,0 +1,92 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.core.ui
 | 
			
		||||
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import dev.inmo.jsuikit.elements.Icon
 | 
			
		||||
import dev.inmo.jsuikit.elements.NavItemElement
 | 
			
		||||
import dev.inmo.jsuikit.elements.Navbar
 | 
			
		||||
import dev.inmo.jsuikit.elements.NavbarNav
 | 
			
		||||
import dev.inmo.jsuikit.elements.drawAsLink
 | 
			
		||||
import dev.inmo.jsuikit.modifiers.UIKitBackground
 | 
			
		||||
import dev.inmo.jsuikit.modifiers.UIKitInverse
 | 
			
		||||
import dev.inmo.jsuikit.modifiers.UIKitMargin
 | 
			
		||||
import dev.inmo.jsuikit.modifiers.UIKitModifier
 | 
			
		||||
import dev.inmo.jsuikit.modifiers.UIKitNavbar
 | 
			
		||||
import dev.inmo.jsuikit.modifiers.UIKitPadding
 | 
			
		||||
import dev.inmo.jsuikit.modifiers.UIKitSection
 | 
			
		||||
import dev.inmo.jsuikit.modifiers.UIKitText
 | 
			
		||||
import dev.inmo.jsuikit.modifiers.UIKitTooltipModifier
 | 
			
		||||
import dev.inmo.jsuikit.modifiers.attrsBuilder
 | 
			
		||||
import dev.inmo.jsuikit.modifiers.builder
 | 
			
		||||
import dev.inmo.jsuikit.modifiers.include
 | 
			
		||||
import dev.inmo.jsuikit.utils.AttrsWithContentBuilder
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.models.Config
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.utils.exportGradle
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.utils.openNewConfig
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.utils.saveConfig
 | 
			
		||||
import org.jetbrains.compose.web.dom.A
 | 
			
		||||
import org.jetbrains.compose.web.dom.Div
 | 
			
		||||
import org.jetbrains.compose.web.dom.Img
 | 
			
		||||
import org.jetbrains.compose.web.dom.Section
 | 
			
		||||
import org.jetbrains.compose.web.dom.Text
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
actual fun TopAppBar(
 | 
			
		||||
    config: Config,
 | 
			
		||||
    saveAvailable: Boolean,
 | 
			
		||||
    onSaveAvailable: (Boolean) -> Unit,
 | 
			
		||||
    onNewConfig: (Config) -> Unit
 | 
			
		||||
) {
 | 
			
		||||
    Section(attrsBuilder(UIKitSection.Style.Primary, UIKitInverse.Light)) {
 | 
			
		||||
        Navbar(
 | 
			
		||||
            leftBuilder = AttrsWithContentBuilder {
 | 
			
		||||
                Div(
 | 
			
		||||
                    {
 | 
			
		||||
                        onClick {
 | 
			
		||||
                            console.log(config)
 | 
			
		||||
                        }
 | 
			
		||||
                        include(UIKitPadding.Size.Small, UIKitText.Style.Lead)
 | 
			
		||||
                    }
 | 
			
		||||
                ) {
 | 
			
		||||
                    Text("Kotlin publication scripts builder")
 | 
			
		||||
                }
 | 
			
		||||
                Div(UIKitMargin.Small.builder()) {
 | 
			
		||||
                    A("https://github.com/InsanusMokrassar/KotlinPublicationScriptsBuilder") {
 | 
			
		||||
                        Img("https://img.shields.io/github/stars/InsanusMokrassar/KotlinPublicationScriptsBuilder?label=Github&style=plastic")
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            rightBuilder = AttrsWithContentBuilder {
 | 
			
		||||
                NavbarNav(
 | 
			
		||||
                    AttrsWithContentBuilder {
 | 
			
		||||
                        NavItemElement(
 | 
			
		||||
                            UIKitTooltipModifier("Open file")
 | 
			
		||||
                        ) {
 | 
			
		||||
                            Icon.Storage.Pull.drawAsLink {
 | 
			
		||||
                                openNewConfig(onNewConfig)
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    },
 | 
			
		||||
                    AttrsWithContentBuilder {
 | 
			
		||||
                        NavItemElement(
 | 
			
		||||
                            UIKitTooltipModifier("Save config")
 | 
			
		||||
                        ) {
 | 
			
		||||
                            Icon.Storage.Push.drawAsLink {
 | 
			
		||||
                                saveConfig(config)
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    },
 | 
			
		||||
                    AttrsWithContentBuilder {
 | 
			
		||||
                        NavItemElement(
 | 
			
		||||
                            UIKitTooltipModifier("Export gradle script")
 | 
			
		||||
                        ) {
 | 
			
		||||
                            Icon.Storage.Upload.drawAsLink {
 | 
			
		||||
                                exportGradle(config)
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    },
 | 
			
		||||
                )
 | 
			
		||||
            },
 | 
			
		||||
            navModifiers = arrayOf(UIKitNavbar.Transparent)
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,23 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.core.ui
 | 
			
		||||
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import dev.inmo.jsuikit.modifiers.UIKitForm
 | 
			
		||||
import dev.inmo.jsuikit.modifiers.builder
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.DefaultSmallVerticalMargin
 | 
			
		||||
import org.jetbrains.compose.web.dom.Legend
 | 
			
		||||
import org.jetbrains.compose.web.dom.Text
 | 
			
		||||
 | 
			
		||||
actual abstract class View {
 | 
			
		||||
    @Composable
 | 
			
		||||
    actual abstract fun build()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
actual fun View.DrawVertically(title: String, block: @Composable () -> Unit) {
 | 
			
		||||
    Legend(UIKitForm.Legend.builder()) {
 | 
			
		||||
        Text(title)
 | 
			
		||||
    }
 | 
			
		||||
    DefaultSmallVerticalMargin()
 | 
			
		||||
    block()
 | 
			
		||||
    DefaultSmallVerticalMargin()
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,128 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.core.ui.utils
 | 
			
		||||
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import dev.inmo.jsuikit.elements.DefaultButton
 | 
			
		||||
import dev.inmo.jsuikit.elements.DefaultInput
 | 
			
		||||
import dev.inmo.jsuikit.elements.Divider
 | 
			
		||||
import dev.inmo.jsuikit.elements.Flex
 | 
			
		||||
import dev.inmo.jsuikit.elements.Icon
 | 
			
		||||
import dev.inmo.jsuikit.elements.drawAsFormInputPart
 | 
			
		||||
import dev.inmo.jsuikit.modifiers.UIKitButton
 | 
			
		||||
import dev.inmo.jsuikit.modifiers.UIKitFlex
 | 
			
		||||
import dev.inmo.jsuikit.modifiers.UIKitForm
 | 
			
		||||
import dev.inmo.jsuikit.modifiers.UIKitInverse
 | 
			
		||||
import dev.inmo.jsuikit.modifiers.UIKitMargin
 | 
			
		||||
import dev.inmo.jsuikit.modifiers.UIKitUtility
 | 
			
		||||
import dev.inmo.jsuikit.modifiers.attrsBuilder
 | 
			
		||||
import dev.inmo.jsuikit.modifiers.builder
 | 
			
		||||
import dev.inmo.jsuikit.modifiers.include
 | 
			
		||||
import kotlinx.browser.window
 | 
			
		||||
import org.jetbrains.compose.web.attributes.InputType
 | 
			
		||||
import org.jetbrains.compose.web.dom.Div
 | 
			
		||||
import org.jetbrains.compose.web.dom.Legend
 | 
			
		||||
import org.jetbrains.compose.web.dom.Text
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
actual fun TitleText(text: String) {
 | 
			
		||||
    Legend(UIKitForm.Legend.builder()) {
 | 
			
		||||
        Text(text)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
actual fun CommonText(text: String, onClick: (() -> Unit)?) {
 | 
			
		||||
    Div(
 | 
			
		||||
        {
 | 
			
		||||
            onClick ?.let {
 | 
			
		||||
                this.onClick { _ ->
 | 
			
		||||
                    it()
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    ) {
 | 
			
		||||
        Text(text)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
actual fun CommonTextField(
 | 
			
		||||
    presetText: String,
 | 
			
		||||
    hint: String?,
 | 
			
		||||
    onFocusChanged: (Boolean) -> Unit,
 | 
			
		||||
    onChange: (String) -> Unit
 | 
			
		||||
) {
 | 
			
		||||
    DefaultInput(
 | 
			
		||||
        InputType.Text,
 | 
			
		||||
        presetText,
 | 
			
		||||
        false,
 | 
			
		||||
        placeholder = hint,
 | 
			
		||||
        attributesCustomizer = {
 | 
			
		||||
            onFocusIn { onFocusChanged(true) }
 | 
			
		||||
            onFocusOut {
 | 
			
		||||
                window.setTimeout( // avoid immediate hiding of potential interface data with additional delay
 | 
			
		||||
                    { onFocusChanged(false) },
 | 
			
		||||
                    100
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        onChange = onChange
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
actual fun SwitchWithLabel(
 | 
			
		||||
    label: String,
 | 
			
		||||
    checked: Boolean,
 | 
			
		||||
    placeSwitchAtTheStart: Boolean,
 | 
			
		||||
    switchEnabled: Boolean,
 | 
			
		||||
    onCheckedChange: (Boolean) -> Unit
 | 
			
		||||
) {
 | 
			
		||||
    DefaultButton(
 | 
			
		||||
        if (checked) {
 | 
			
		||||
            UIKitButton.Type.Primary
 | 
			
		||||
        } else {
 | 
			
		||||
            UIKitButton.Type.Default
 | 
			
		||||
        },
 | 
			
		||||
        disabled = !switchEnabled,
 | 
			
		||||
        onClick = {
 | 
			
		||||
            onCheckedChange(!checked)
 | 
			
		||||
        },
 | 
			
		||||
        attributesCustomizer = {
 | 
			
		||||
            include(UIKitUtility.Inline, UIKitUtility.NoTransform, UIKitUtility.Border.Rounded)
 | 
			
		||||
        }
 | 
			
		||||
    ) {
 | 
			
		||||
        if (checked) {
 | 
			
		||||
            Icon.App.Check.drawAsFormInputPart(UIKitInverse.Light)
 | 
			
		||||
        }
 | 
			
		||||
        Text(label)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
actual fun <T> ButtonsPanel(
 | 
			
		||||
    title: String,
 | 
			
		||||
    data: Iterable<T>,
 | 
			
		||||
    itemDrawer: @Composable (T) -> Unit
 | 
			
		||||
) {
 | 
			
		||||
    Flex(UIKitFlex.Alignment.Vertical.Middle, UIKitMargin.Small) {
 | 
			
		||||
        Div(UIKitMargin.Small.Horizontal.builder()) { Text(title) }
 | 
			
		||||
        data.forEach { itemDrawer(it) }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
actual fun DefaultDivider() {
 | 
			
		||||
    Divider.Common()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
actual fun DefaultSmallVerticalMargin() {
 | 
			
		||||
    Div(UIKitMargin.Small.Top.builder())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
actual fun DefaultContentColumn(block: @Composable () -> Unit) {
 | 
			
		||||
    Div(attrsBuilder(UIKitMargin.Small.Horizontal, UIKitMargin.Small.Vertical)) {
 | 
			
		||||
        block()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,9 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.core.ui.utils
 | 
			
		||||
 | 
			
		||||
import dev.inmo.jsuikit.modifiers.UIKitCustom
 | 
			
		||||
import dev.inmo.jsuikit.modifiers.UIKitUtility
 | 
			
		||||
 | 
			
		||||
val ClassNoTransform = UIKitCustom(arrayOf("no-transform"))
 | 
			
		||||
 | 
			
		||||
val UIKitUtility.Companion.NoTransform
 | 
			
		||||
    get() = ClassNoTransform
 | 
			
		||||
@@ -0,0 +1,83 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.core.utils
 | 
			
		||||
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.models.Config
 | 
			
		||||
import kotlinx.browser.document
 | 
			
		||||
import kotlinx.dom.appendElement
 | 
			
		||||
import org.w3c.dom.HTMLAnchorElement
 | 
			
		||||
import org.w3c.dom.HTMLInputElement
 | 
			
		||||
import org.w3c.dom.url.URL
 | 
			
		||||
import org.w3c.files.Blob
 | 
			
		||||
import org.w3c.files.BlobPropertyBag
 | 
			
		||||
import org.w3c.files.FileReader
 | 
			
		||||
import org.w3c.files.get
 | 
			
		||||
 | 
			
		||||
fun saveFile(content: String, filename: String) {
 | 
			
		||||
    val a = document.body!!.appendElement("a") {
 | 
			
		||||
        setAttribute("style", "visibility:hidden; display: none")
 | 
			
		||||
    } as HTMLAnchorElement
 | 
			
		||||
    val blob = Blob(arrayOf(content), BlobPropertyBag(
 | 
			
		||||
        "application/*;charset=utf-8"
 | 
			
		||||
    ))
 | 
			
		||||
    val url = URL.createObjectURL(blob)
 | 
			
		||||
    a.href = url
 | 
			
		||||
    a.download = filename
 | 
			
		||||
    a.click()
 | 
			
		||||
    URL.revokeObjectURL(url)
 | 
			
		||||
    a.remove()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
actual fun openNewConfig(onParsed: (Config) -> Unit) {
 | 
			
		||||
    val targetInput = document.body!!.appendElement("input") {
 | 
			
		||||
        setAttribute("style", "visibility:hidden; display: none")
 | 
			
		||||
    } as HTMLInputElement
 | 
			
		||||
    targetInput.type = "file"
 | 
			
		||||
    targetInput.onchange = {
 | 
			
		||||
        targetInput.files ?.also { files ->
 | 
			
		||||
            for (i in (0 until files.length) ) {
 | 
			
		||||
                files[i] ?.also { file ->
 | 
			
		||||
                    val reader = FileReader()
 | 
			
		||||
 | 
			
		||||
                    reader.onload = {
 | 
			
		||||
                        val content = it.target.asDynamic().result as String
 | 
			
		||||
                        onParsed(serialFormat.decodeFromString(Config.serializer(), content))
 | 
			
		||||
                        false
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    reader.readAsText(file)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    targetInput.click()
 | 
			
		||||
    targetInput.remove()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
actual fun saveConfig(config: Config): Boolean {
 | 
			
		||||
    saveFile(
 | 
			
		||||
        serialFormat.encodeToString(Config.serializer(), config),
 | 
			
		||||
        "publish.kpsb"
 | 
			
		||||
    )
 | 
			
		||||
    return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
actual fun exportGradle(config: Config): Boolean {
 | 
			
		||||
    val filename = "publish.gradle"
 | 
			
		||||
 | 
			
		||||
    val content = config.run {
 | 
			
		||||
        type.buildMavenGradleConfig(
 | 
			
		||||
            mavenConfig,
 | 
			
		||||
            licenses
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    saveFile(content, filename)
 | 
			
		||||
    return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
actual fun saveAs(config: Config): Boolean {
 | 
			
		||||
    saveFile(
 | 
			
		||||
        serialFormat.encodeToString(Config.serializer(), config),
 | 
			
		||||
        "publish.kpsb"
 | 
			
		||||
    )
 | 
			
		||||
    return true
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,6 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.core.utils
 | 
			
		||||
 | 
			
		||||
actual fun openLink(link: String): Boolean {
 | 
			
		||||
    dev.inmo.micro_utils.common.openLink(link)
 | 
			
		||||
    return true
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										4
									
								
								core/src/jsMain/resources/css/internal.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,4 @@
 | 
			
		||||
.no-transform {
 | 
			
		||||
    text-transform: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1
									
								
								core/src/jsMain/resources/css/uikit.min.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										73
									
								
								core/src/jsMain/resources/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,73 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<html lang="en">
 | 
			
		||||
<head>
 | 
			
		||||
    <meta charset="UTF-8">
 | 
			
		||||
    <title>Kotlin Publication Scripts Builder</title>
 | 
			
		||||
    <!-- UIkit CSS -->
 | 
			
		||||
    <link rel="stylesheet" href="./css/uikit.min.css" />
 | 
			
		||||
    <link rel="stylesheet" href="./css/internal.css" />
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
<!--    <form class="uk-padding-small">-->
 | 
			
		||||
<!--        <fieldset class="uk-fieldset">-->
 | 
			
		||||
<!--            <legend class="uk-legend">Project type</legend>-->
 | 
			
		||||
<!--            <div class="uk-padding-small">-->
 | 
			
		||||
<!--                <ul class="uk-subnav uk-subnav-pill">-->
 | 
			
		||||
<!--                    <li id="mppProjectType" class="uk-active"><a href="#">Multiplatform</a></li>-->
 | 
			
		||||
<!--                    <li id="jvmProjectType"><a href="#">JVM</a></li>-->
 | 
			
		||||
<!--                    <li id="jsProjectType"><a href="#">JS</a></li>-->
 | 
			
		||||
<!--                </ul>-->
 | 
			
		||||
<!--            </div>-->
 | 
			
		||||
<!--            <legend class="uk-legend">Licenses</legend>-->
 | 
			
		||||
<!--            <div id="licensesListDiv" class="uk-padding-small"></div>-->
 | 
			
		||||
 | 
			
		||||
<!--            <legend class="uk-legend">Project information</legend>-->
 | 
			
		||||
 | 
			
		||||
<!--            <div class="uk-padding-small">-->
 | 
			
		||||
<!--                <div class="uk-margin uk-width-1-1">-->
 | 
			
		||||
<!--                    <label class="uk-form-label" for="projectNameInput">Public project name</label>-->
 | 
			
		||||
<!--                    <input id="projectNameInput" class="uk-input uk-width-expand" type="text" placeholder="${project.name}">-->
 | 
			
		||||
<!--                </div>-->
 | 
			
		||||
<!--                <div class="uk-margin uk-width-1-1">-->
 | 
			
		||||
<!--                    <label class="uk-form-label" for="projectDescriptionInput">Public project description</label>-->
 | 
			
		||||
<!--                    <input id="projectDescriptionInput" class="uk-input uk-width-expand" type="text" placeholder="${project.name}">-->
 | 
			
		||||
<!--                </div>-->
 | 
			
		||||
<!--                <div class="uk-margin uk-width-1-1">-->
 | 
			
		||||
<!--                    <label class="uk-form-label" for="projectUrlInput">Public project URL</label>-->
 | 
			
		||||
<!--                    <input id="projectUrlInput" class="uk-input uk-width-expand" type="text" placeholder="Type url to github or other source with readme">-->
 | 
			
		||||
<!--                </div>-->
 | 
			
		||||
<!--                <div class="uk-margin uk-width-1-1">-->
 | 
			
		||||
<!--                    <label class="uk-form-label" for="projectVCSUrlInput">Public project VCS URL (with .git)</label>-->
 | 
			
		||||
<!--                    <input id="projectVCSUrlInput" class="uk-input uk-width-expand" type="text" placeholder="Type url to github .git file">-->
 | 
			
		||||
<!--                </div>-->
 | 
			
		||||
 | 
			
		||||
<!--                <div class="uk-margin">-->
 | 
			
		||||
<!--                    <label>GPG Signing</label>-->
 | 
			
		||||
 | 
			
		||||
<!--                    <div class="uk-padding-small">-->
 | 
			
		||||
<!--                        <ul class="uk-subnav uk-subnav-pill">-->
 | 
			
		||||
<!--                            <li id="disableGpgSigning" class="uk-active" uk-tooltip="title: Signing will not be added"><a href="#">Disabled</a></li>-->
 | 
			
		||||
<!--                            <li id="optionalGpgSigning" uk-tooltip="title: Signing will be added, but disabled in case of absence 'signatory.keyId'"><a href="#">Optional</a></li>-->
 | 
			
		||||
<!--                            <li id="enableGpgSigning" uk-tooltip="title: Signing will be always enabled"><a href="#">Enabled</a></li>-->
 | 
			
		||||
<!--                        </ul>-->
 | 
			
		||||
<!--                    </div>-->
 | 
			
		||||
<!--                </div>-->
 | 
			
		||||
<!--                <div class="uk-margin">-->
 | 
			
		||||
<!--                    <label><input id="includeMavenCentralTargetRepoToggle" class="uk-checkbox" type="checkbox"> Include publication to MavenCentral</label>-->
 | 
			
		||||
<!--                </div>-->
 | 
			
		||||
<!--            </div>-->
 | 
			
		||||
 | 
			
		||||
<!--            <legend class="uk-legend">Developers info</legend>-->
 | 
			
		||||
<!--            <div id="developersListDiv" class="uk-padding-small"></div>-->
 | 
			
		||||
 | 
			
		||||
<!--            <legend class="uk-legend">Repositories info</legend>-->
 | 
			
		||||
<!--            <div id="repositoriesListDiv" class="uk-padding-small"></div>-->
 | 
			
		||||
<!--        </fieldset>-->
 | 
			
		||||
<!--    </form>-->
 | 
			
		||||
    <!-- UIkit JS -->
 | 
			
		||||
    <script src="./js/uikit.min.js"></script>
 | 
			
		||||
    <script src="./js/uikit-icons.min.js"></script>
 | 
			
		||||
    <!-- Internal JS -->
 | 
			
		||||
    <script src="kmppscriptbuilder.core.js"></script>
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
							
								
								
									
										1
									
								
								core/src/jsMain/resources/js/uikit-icons.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										1
									
								
								core/src/jsMain/resources/js/uikit.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						@@ -1,4 +1,4 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.desktop
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.core
 | 
			
		||||
 | 
			
		||||
import androidx.compose.foundation.*
 | 
			
		||||
import androidx.compose.foundation.layout.*
 | 
			
		||||
@@ -9,9 +9,8 @@ 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.desktop.utils.init
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.desktop.utils.loadConfigFile
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.desktop.views.BuilderView
 | 
			
		||||
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)
 | 
			
		||||
@@ -48,7 +47,9 @@ fun main(args: Array<String>) = application {
 | 
			
		||||
                        .fillMaxSize()
 | 
			
		||||
                        .verticalScroll(stateVertical)
 | 
			
		||||
                ) {
 | 
			
		||||
                    builder.init()
 | 
			
		||||
                    Column {
 | 
			
		||||
                        builder.build()
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,33 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.core.ui
 | 
			
		||||
 | 
			
		||||
import androidx.compose.foundation.layout.Column
 | 
			
		||||
import androidx.compose.foundation.layout.Spacer
 | 
			
		||||
import androidx.compose.foundation.layout.fillMaxWidth
 | 
			
		||||
import androidx.compose.foundation.layout.height
 | 
			
		||||
import androidx.compose.foundation.layout.padding
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.compose.ui.unit.dp
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.DefaultSmallVerticalMargin
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.TitleText
 | 
			
		||||
 | 
			
		||||
actual abstract class View {
 | 
			
		||||
    internal open val defaultModifier = Modifier.fillMaxWidth()
 | 
			
		||||
    @Composable
 | 
			
		||||
    actual abstract fun build()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
actual fun View.DrawVertically(
 | 
			
		||||
    title: String,
 | 
			
		||||
    block: @Composable () -> Unit
 | 
			
		||||
) {
 | 
			
		||||
    TitleText(title)
 | 
			
		||||
    DefaultSmallVerticalMargin()
 | 
			
		||||
 | 
			
		||||
    Column(defaultModifier) {
 | 
			
		||||
        block()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    DefaultSmallVerticalMargin()
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,39 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.core.ui
 | 
			
		||||
 | 
			
		||||
import androidx.compose.foundation.layout.Row
 | 
			
		||||
import androidx.compose.foundation.layout.padding
 | 
			
		||||
import androidx.compose.material.Button
 | 
			
		||||
import androidx.compose.material.OutlinedButton
 | 
			
		||||
import androidx.compose.material.Text
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.ui.Alignment
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.compose.ui.unit.dp
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.models.GpgSigning
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.CommonTextField
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.Drawer
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.SwitchWithLabel
 | 
			
		||||
 | 
			
		||||
actual class GpgSigningOptionDrawer(
 | 
			
		||||
    private val mavenInfoView: MavenInfoView
 | 
			
		||||
) : Drawer<GpgSigning> {
 | 
			
		||||
    @Composable
 | 
			
		||||
    override fun GpgSigning.draw() {
 | 
			
		||||
        if (mavenInfoView.gpgSignProperty == this) {
 | 
			
		||||
            Button({}, Modifier.padding(8.dp, 0.dp)) {
 | 
			
		||||
                Text(name)
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            OutlinedButton(
 | 
			
		||||
                {
 | 
			
		||||
                    mavenInfoView.gpgSignProperty = this
 | 
			
		||||
                },
 | 
			
		||||
                Modifier.padding(8.dp, 0.dp)
 | 
			
		||||
            ) {
 | 
			
		||||
                Text(name)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
actual fun GpgSigningOptionDrawerWithView(view: MavenInfoView): GpgSigningOptionDrawer = GpgSigningOptionDrawer(mavenInfoView = view)
 | 
			
		||||
@@ -0,0 +1,31 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.core.ui
 | 
			
		||||
 | 
			
		||||
import androidx.compose.foundation.layout.Column
 | 
			
		||||
import androidx.compose.foundation.layout.padding
 | 
			
		||||
import androidx.compose.material.Button
 | 
			
		||||
import androidx.compose.material.Divider
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.compose.ui.unit.dp
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.CommonText
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.CommonTextField
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.Drawer
 | 
			
		||||
 | 
			
		||||
actual object LicensesDrawer : Drawer<LicensesView> {
 | 
			
		||||
    @Composable
 | 
			
		||||
    override fun LicensesView.draw() {
 | 
			
		||||
        if (searchFieldFocused.value) {
 | 
			
		||||
            Column {
 | 
			
		||||
                licensesOffersToShow.value.forEach {
 | 
			
		||||
                    Column(Modifier.padding(16.dp, 8.dp, 8.dp, 8.dp)) {
 | 
			
		||||
                        CommonText(it.title) {
 | 
			
		||||
                            itemsList.add(it.toLicenseState())
 | 
			
		||||
                            licenseSearchFilter = ""
 | 
			
		||||
                        }
 | 
			
		||||
                        Divider()
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,33 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.core.ui
 | 
			
		||||
 | 
			
		||||
import androidx.compose.foundation.layout.padding
 | 
			
		||||
import androidx.compose.material.Button
 | 
			
		||||
import androidx.compose.material.OutlinedButton
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.compose.ui.unit.dp
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.CommonText
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.DefaultContentColumn
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.Drawer
 | 
			
		||||
 | 
			
		||||
actual class ListViewDrawer<T> : Drawer<ListView<T>> {
 | 
			
		||||
    @Composable
 | 
			
		||||
    override fun ListView<T>.draw() {
 | 
			
		||||
        itemsList.forEach { item ->
 | 
			
		||||
            DefaultContentColumn {
 | 
			
		||||
                buildView(item)
 | 
			
		||||
                OutlinedButton({ itemsList.remove(item) }, Modifier.padding(8.dp)) {
 | 
			
		||||
                    CommonText(removeItemText,)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            Button({ itemsList.add(createItem()) }) {
 | 
			
		||||
                CommonText(addItemText,)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (itemsList.isEmpty()) {
 | 
			
		||||
            Button({ itemsList.add(createItem()) }) {
 | 
			
		||||
                CommonText(addItemText,)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,40 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.core.ui
 | 
			
		||||
 | 
			
		||||
import androidx.compose.foundation.layout.Row
 | 
			
		||||
import androidx.compose.foundation.layout.padding
 | 
			
		||||
import androidx.compose.material.Button
 | 
			
		||||
import androidx.compose.material.OutlinedButton
 | 
			
		||||
import androidx.compose.material.Text
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.ui.Alignment
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.compose.ui.unit.dp
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.models.JSProjectType
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.models.JVMProjectType
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.models.MultiplatformProjectType
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.models.ProjectType
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.Drawer
 | 
			
		||||
 | 
			
		||||
actual class ProjectTypeDrawer(
 | 
			
		||||
    private val projectTypeView: ProjectTypeView
 | 
			
		||||
) : Drawer<ProjectType> {
 | 
			
		||||
    @Composable
 | 
			
		||||
    override fun ProjectType.draw() {
 | 
			
		||||
        if (projectTypeView.projectType == this) {
 | 
			
		||||
            Button({}, Modifier.padding(8.dp, 0.dp)) {
 | 
			
		||||
                Text(name)
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            OutlinedButton(
 | 
			
		||||
                {
 | 
			
		||||
                    projectTypeView.projectType = this
 | 
			
		||||
                },
 | 
			
		||||
                Modifier.padding(8.dp, 0.dp)
 | 
			
		||||
            ) {
 | 
			
		||||
                Text(name)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
actual fun ProjectTypeDrawerWithView(view: ProjectTypeView): ProjectTypeDrawer = ProjectTypeDrawer(projectTypeView = view)
 | 
			
		||||
@@ -0,0 +1,40 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.core.ui
 | 
			
		||||
 | 
			
		||||
import androidx.compose.foundation.layout.padding
 | 
			
		||||
import androidx.compose.material.Button
 | 
			
		||||
import androidx.compose.material.OutlinedButton
 | 
			
		||||
import androidx.compose.material.Text
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.compose.ui.unit.dp
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.models.MavenPublishingRepository
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.ui.utils.Drawer
 | 
			
		||||
 | 
			
		||||
actual class RepositoryCredentialTypeDrawer(
 | 
			
		||||
    private val state: RepositoryState
 | 
			
		||||
) : Drawer<MavenPublishingRepository.CredentialsType> {
 | 
			
		||||
    @Composable
 | 
			
		||||
    override fun MavenPublishingRepository.CredentialsType.draw() {
 | 
			
		||||
        val name = when (this@draw) {
 | 
			
		||||
            is MavenPublishingRepository.CredentialsType.HttpHeaderCredentials -> "Headers"
 | 
			
		||||
            MavenPublishingRepository.CredentialsType.Nothing -> "No"
 | 
			
		||||
            is MavenPublishingRepository.CredentialsType.UsernameAndPassword -> "Username and password"
 | 
			
		||||
        }
 | 
			
		||||
        if (state.credsType == this) {
 | 
			
		||||
            Button({}, Modifier.padding(8.dp, 0.dp)) {
 | 
			
		||||
                Text(name)
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            OutlinedButton(
 | 
			
		||||
                {
 | 
			
		||||
                    state.credsType = this
 | 
			
		||||
                },
 | 
			
		||||
                Modifier.padding(8.dp, 0.dp)
 | 
			
		||||
            ) {
 | 
			
		||||
                Text(name)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
actual fun RepositoryCredentialTypeDrawerWithState(repositoryState: RepositoryState): RepositoryCredentialTypeDrawer = RepositoryCredentialTypeDrawer(repositoryState)
 | 
			
		||||
@@ -0,0 +1,88 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.core.ui
 | 
			
		||||
 | 
			
		||||
import androidx.compose.foundation.ExperimentalFoundationApi
 | 
			
		||||
import androidx.compose.foundation.Image
 | 
			
		||||
import androidx.compose.foundation.TooltipArea
 | 
			
		||||
import androidx.compose.foundation.clickable
 | 
			
		||||
import androidx.compose.foundation.layout.padding
 | 
			
		||||
import androidx.compose.foundation.shape.RoundedCornerShape
 | 
			
		||||
import androidx.compose.material.IconButton
 | 
			
		||||
import androidx.compose.material.MaterialTheme
 | 
			
		||||
import androidx.compose.material.Surface
 | 
			
		||||
import androidx.compose.material.Text
 | 
			
		||||
import androidx.compose.material.TopAppBar
 | 
			
		||||
import androidx.compose.material.primarySurface
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.compose.ui.draw.shadow
 | 
			
		||||
import androidx.compose.ui.res.painterResource
 | 
			
		||||
import androidx.compose.ui.unit.dp
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.models.Config
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.utils.exportGradle
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.utils.openNewConfig
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.utils.saveAs
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.utils.saveConfig
 | 
			
		||||
 | 
			
		||||
@OptIn(ExperimentalFoundationApi::class)
 | 
			
		||||
@Composable
 | 
			
		||||
private fun createIcon(
 | 
			
		||||
    tooltip: String,
 | 
			
		||||
    resource: String,
 | 
			
		||||
    onClick: () -> Unit
 | 
			
		||||
) {
 | 
			
		||||
    TooltipArea(
 | 
			
		||||
        tooltip = {
 | 
			
		||||
            Surface(
 | 
			
		||||
                modifier = Modifier.shadow(4.dp),
 | 
			
		||||
                color = MaterialTheme.colors.primarySurface,
 | 
			
		||||
                shape = RoundedCornerShape(4.dp)
 | 
			
		||||
            ) {
 | 
			
		||||
                Text(tooltip, modifier = Modifier.padding(10.dp), color = MaterialTheme.colors.onPrimary)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    ) {
 | 
			
		||||
        IconButton(onClick) {
 | 
			
		||||
            Image(
 | 
			
		||||
                painter = painterResource(resource),
 | 
			
		||||
                contentDescription = tooltip
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
actual fun TopAppBar(
 | 
			
		||||
    config: Config,
 | 
			
		||||
    saveAvailable: Boolean,
 | 
			
		||||
    onSaveAvailable: (Boolean) -> Unit,
 | 
			
		||||
    onNewConfig: (Config) -> Unit
 | 
			
		||||
) {
 | 
			
		||||
    TopAppBar(
 | 
			
		||||
        @Composable {
 | 
			
		||||
            Text("Kotlin publication scripts builder", Modifier.clickable { println(config) })
 | 
			
		||||
        },
 | 
			
		||||
        actions = {
 | 
			
		||||
            createIcon("Open file", "images/open_file.svg") {
 | 
			
		||||
                openNewConfig(onNewConfig)
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (saveAvailable) {
 | 
			
		||||
                createIcon("Save", "images/save_file.svg") {
 | 
			
		||||
                    saveConfig(config)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (saveAvailable) {
 | 
			
		||||
                createIcon("Export Gradle script", "images/export_gradle.svg") {
 | 
			
		||||
                    exportGradle(config)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            createIcon("Save as", "images/save_as.svg") {
 | 
			
		||||
                if (saveAs(config)) {
 | 
			
		||||
                    onSaveAvailable(true)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,113 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.core.ui.utils
 | 
			
		||||
 | 
			
		||||
import androidx.compose.foundation.clickable
 | 
			
		||||
import androidx.compose.foundation.layout.Arrangement
 | 
			
		||||
import androidx.compose.foundation.layout.Box
 | 
			
		||||
import androidx.compose.foundation.layout.Column
 | 
			
		||||
import androidx.compose.foundation.layout.Row
 | 
			
		||||
import androidx.compose.foundation.layout.Spacer
 | 
			
		||||
import androidx.compose.foundation.layout.fillMaxWidth
 | 
			
		||||
import androidx.compose.foundation.layout.padding
 | 
			
		||||
import androidx.compose.material.Divider
 | 
			
		||||
import androidx.compose.material.OutlinedTextField
 | 
			
		||||
import androidx.compose.material.Switch
 | 
			
		||||
import androidx.compose.material.Text
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.ui.Alignment
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.compose.ui.focus.onFocusChanged
 | 
			
		||||
import androidx.compose.ui.text.TextStyle
 | 
			
		||||
import androidx.compose.ui.unit.dp
 | 
			
		||||
import androidx.compose.ui.unit.sp
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
val commonTextFieldTextStyle = TextStyle(
 | 
			
		||||
    fontSize = 12.sp
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
actual fun SwitchWithLabel(
 | 
			
		||||
    label: String,
 | 
			
		||||
    checked: Boolean,
 | 
			
		||||
    placeSwitchAtTheStart: Boolean,
 | 
			
		||||
    switchEnabled: Boolean,
 | 
			
		||||
    onCheckedChange: (Boolean) -> Unit
 | 
			
		||||
) {
 | 
			
		||||
    Row(Modifier.padding(0.dp, 8.dp).clickable { onCheckedChange(!checked) }, Arrangement.Start, Alignment.Top) {
 | 
			
		||||
        val switchCreator = @Composable {
 | 
			
		||||
            Switch(checked, null, Modifier.padding(8.dp, 0.dp), enabled = switchEnabled)
 | 
			
		||||
        }
 | 
			
		||||
        if (placeSwitchAtTheStart) {
 | 
			
		||||
            switchCreator()
 | 
			
		||||
        }
 | 
			
		||||
        Box(Modifier.fillMaxWidth().align(Alignment.CenterVertically)) {
 | 
			
		||||
            CommonText(label)
 | 
			
		||||
        }
 | 
			
		||||
        if (!placeSwitchAtTheStart) {
 | 
			
		||||
            switchCreator()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
actual fun CommonTextField(
 | 
			
		||||
    presetText: String,
 | 
			
		||||
    hint: String?,
 | 
			
		||||
    onFocusChanged: (Boolean) -> Unit,
 | 
			
		||||
    onChange: (String) -> Unit
 | 
			
		||||
) {
 | 
			
		||||
    OutlinedTextField(
 | 
			
		||||
        presetText,
 | 
			
		||||
        onChange,
 | 
			
		||||
        Modifier.fillMaxWidth().onFocusChanged {
 | 
			
		||||
            onFocusChanged(it.isFocused)
 | 
			
		||||
        },
 | 
			
		||||
        singleLine = true,
 | 
			
		||||
        label = hint ?.let {
 | 
			
		||||
            {
 | 
			
		||||
                CommonText(hint)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
actual fun CommonText(text: String, onClick: (() -> Unit)?) {
 | 
			
		||||
    Text(text, modifier = Modifier.run { onClick ?.let { clickable(onClick = it) } ?: this })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
actual fun TitleText(text: String) {
 | 
			
		||||
    Text(
 | 
			
		||||
        text, Modifier.padding(0.dp, 8.dp), fontSize = 18.sp
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
actual fun <T> ButtonsPanel(
 | 
			
		||||
    title: String,
 | 
			
		||||
    data: Iterable<T>,
 | 
			
		||||
    itemDrawer: @Composable (T) -> Unit
 | 
			
		||||
) {
 | 
			
		||||
    Row {
 | 
			
		||||
        Text(title, Modifier.padding(8.dp))
 | 
			
		||||
        data.forEach { itemDrawer(it) }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
actual fun DefaultDivider() {
 | 
			
		||||
    Divider()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
actual fun DefaultSmallVerticalMargin() {
 | 
			
		||||
    Spacer(Modifier.padding(0.dp, 4.dp))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
actual fun DefaultContentColumn(block: @Composable () -> Unit) {
 | 
			
		||||
    Column(Modifier.padding(8.dp)) {
 | 
			
		||||
        block()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.desktop.utils
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.core.ui.utils
 | 
			
		||||
 | 
			
		||||
import java.io.File
 | 
			
		||||
import javax.swing.filechooser.FileFilter
 | 
			
		||||
@@ -1,40 +1,40 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.desktop.utils
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.core.utils
 | 
			
		||||
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.models.Config
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.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")))
 | 
			
		||||
@@ -1,9 +1,9 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.desktop.utils
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.core.utils
 | 
			
		||||
 | 
			
		||||
import java.awt.Desktop
 | 
			
		||||
import java.net.URI
 | 
			
		||||
 | 
			
		||||
fun openLink(link: String): Boolean {
 | 
			
		||||
actual fun openLink(link: String): Boolean {
 | 
			
		||||
    val desktop = if (Desktop.isDesktopSupported()) Desktop.getDesktop() else null
 | 
			
		||||
    if (desktop != null && desktop.isSupported(Desktop.Action.BROWSE)) {
 | 
			
		||||
        try {
 | 
			
		||||
@@ -0,0 +1,2 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.core.utils 
 | 
			
		||||
 | 
			
		||||
@@ -1 +0,0 @@
 | 
			
		||||
<manifest package="dev.inmo.KotlinPublicationScriptsBuilder.core"/>
 | 
			
		||||
@@ -1,40 +0,0 @@
 | 
			
		||||
apply plugin: 'com.getkeepsafe.dexcount'
 | 
			
		||||
 | 
			
		||||
android {
 | 
			
		||||
    compileSdkVersion "$android_compileSdkVersion".toInteger()
 | 
			
		||||
    buildToolsVersion "$android_buildToolsVersion"
 | 
			
		||||
 | 
			
		||||
    defaultConfig {
 | 
			
		||||
        minSdkVersion "$android_minSdkVersion".toInteger()
 | 
			
		||||
        targetSdkVersion "$android_compileSdkVersion".toInteger()
 | 
			
		||||
        versionCode "${android_code_version}".toInteger()
 | 
			
		||||
        versionName "$version"
 | 
			
		||||
    }
 | 
			
		||||
    buildTypes {
 | 
			
		||||
        release {
 | 
			
		||||
            minifyEnabled false
 | 
			
		||||
        }
 | 
			
		||||
        debug {
 | 
			
		||||
            debuggable true
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    packagingOptions {
 | 
			
		||||
        exclude 'META-INF/kotlinx-serialization-runtime.kotlin_module'
 | 
			
		||||
        exclude 'META-INF/kotlinx-serialization-cbor.kotlin_module'
 | 
			
		||||
        exclude 'META-INF/kotlinx-serialization-properties.kotlin_module'
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    compileOptions {
 | 
			
		||||
        sourceCompatibility JavaVersion.VERSION_1_8
 | 
			
		||||
        targetCompatibility JavaVersion.VERSION_1_8
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    kotlinOptions {
 | 
			
		||||
        jvmTarget = JavaVersion.VERSION_1_8.toString()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    sourceSets {
 | 
			
		||||
        main.java.srcDirs += 'src/main/kotlin'
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,36 +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"
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    sourceSets {
 | 
			
		||||
        commonMain {
 | 
			
		||||
            dependencies {
 | 
			
		||||
                implementation project(":kmppscriptbuilder.core")
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        jvmMain {
 | 
			
		||||
            dependencies {
 | 
			
		||||
                implementation(compose.desktop.currentOs)
 | 
			
		||||
                api "io.ktor:ktor-client-cio:$ktor_version"
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
compose.desktop {
 | 
			
		||||
    application {
 | 
			
		||||
        mainClass = "dev.inmo.kmppscriptbuilder.desktop.BuilderKt"
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1,60 +0,0 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.desktop.utils
 | 
			
		||||
 | 
			
		||||
import androidx.compose.foundation.clickable
 | 
			
		||||
import androidx.compose.foundation.layout.*
 | 
			
		||||
import androidx.compose.material.*
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.ui.Alignment
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.compose.ui.text.TextStyle
 | 
			
		||||
import androidx.compose.ui.unit.dp
 | 
			
		||||
import androidx.compose.ui.unit.sp
 | 
			
		||||
 | 
			
		||||
val commonTextFieldTextStyle = TextStyle(
 | 
			
		||||
    fontSize = 12.sp
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
inline fun TitleText(text: String) = Text(
 | 
			
		||||
    text, Modifier.padding(0.dp, 8.dp), fontSize = 18.sp
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
inline fun CommonText(text: String, modifier: Modifier = Modifier) = Text(
 | 
			
		||||
    text, modifier = modifier
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
inline fun CommonTextField(presetText: String, hint: String, noinline onChange: (String) -> Unit) = OutlinedTextField(
 | 
			
		||||
    presetText,
 | 
			
		||||
    onChange,
 | 
			
		||||
    Modifier.fillMaxWidth(),
 | 
			
		||||
    singleLine = true,
 | 
			
		||||
    label = {
 | 
			
		||||
        CommonText(hint)
 | 
			
		||||
    }
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
inline fun SwitchWithLabel(
 | 
			
		||||
    label: String,
 | 
			
		||||
    checked: Boolean,
 | 
			
		||||
    placeSwitchAtTheStart: Boolean = false,
 | 
			
		||||
    switchEnabled: Boolean = true,
 | 
			
		||||
    modifier: Modifier = Modifier.padding(0.dp, 8.dp),
 | 
			
		||||
    horizontalArrangement: Arrangement.Horizontal = Arrangement.Start,
 | 
			
		||||
    verticalAlignment: Alignment.Vertical = Alignment.Top,
 | 
			
		||||
    switchModifier: Modifier = Modifier.padding(8.dp, 0.dp),
 | 
			
		||||
    noinline onCheckedChange: (Boolean) -> Unit
 | 
			
		||||
) = Row(modifier, horizontalArrangement, verticalAlignment) {
 | 
			
		||||
    val switchCreator = @Composable {
 | 
			
		||||
        Switch(checked, onCheckedChange, switchModifier, enabled = switchEnabled)
 | 
			
		||||
    }
 | 
			
		||||
    if (placeSwitchAtTheStart) {
 | 
			
		||||
        switchCreator()
 | 
			
		||||
    }
 | 
			
		||||
    CommonText(label, Modifier.align(Alignment.CenterVertically).clickable {  })
 | 
			
		||||
    if (!placeSwitchAtTheStart) {
 | 
			
		||||
        switchCreator()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,34 +0,0 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.desktop.utils
 | 
			
		||||
 | 
			
		||||
import androidx.compose.foundation.layout.*
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.compose.ui.unit.dp
 | 
			
		||||
 | 
			
		||||
abstract class View {
 | 
			
		||||
    protected open val defaultModifier = Modifier.fillMaxWidth().padding(8.dp)
 | 
			
		||||
 | 
			
		||||
    @Composable
 | 
			
		||||
    abstract fun build()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
abstract class VerticalView(val title: String) : View() {
 | 
			
		||||
    abstract val content: @Composable ColumnScope.() -> Unit
 | 
			
		||||
    @Composable
 | 
			
		||||
    override fun build() {
 | 
			
		||||
        TitleText(title)
 | 
			
		||||
 | 
			
		||||
        Column(
 | 
			
		||||
            defaultModifier
 | 
			
		||||
        ) {
 | 
			
		||||
            content()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Spacer(Modifier.fillMaxWidth().height(8.dp))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
fun <T : View> T.init(): T = apply {
 | 
			
		||||
    build()
 | 
			
		||||
}
 | 
			
		||||
@@ -1,105 +0,0 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.desktop.views
 | 
			
		||||
 | 
			
		||||
import androidx.compose.foundation.*
 | 
			
		||||
import androidx.compose.foundation.layout.*
 | 
			
		||||
import androidx.compose.foundation.shape.RoundedCornerShape
 | 
			
		||||
import androidx.compose.material.*
 | 
			
		||||
import androidx.compose.runtime.*
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.compose.ui.draw.shadow
 | 
			
		||||
import androidx.compose.ui.graphics.Color
 | 
			
		||||
import androidx.compose.ui.res.painterResource
 | 
			
		||||
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
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    @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
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @OptIn(ExperimentalFoundationApi::class)
 | 
			
		||||
    @Composable
 | 
			
		||||
    override fun build() {
 | 
			
		||||
        Box(Modifier.fillMaxSize()) {
 | 
			
		||||
            Column() {
 | 
			
		||||
                TopAppBar(
 | 
			
		||||
                    @Composable {
 | 
			
		||||
                        CommonText("Kotlin publication scripts builder", Modifier.clickable { println(config) })
 | 
			
		||||
                    },
 | 
			
		||||
                    actions = {
 | 
			
		||||
                        createIcon("Open file", "images/open_file.svg") {
 | 
			
		||||
                            loadConfig()?.also {
 | 
			
		||||
                                config = it
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        if (saveAvailableState) {
 | 
			
		||||
                            createIcon("Save", "images/save_file.svg") {
 | 
			
		||||
                                saveConfig(config)
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        if (saveAvailableState) {
 | 
			
		||||
                            createIcon("Export Gradle script", "images/export_gradle.svg") {
 | 
			
		||||
                                exportGradle(config)
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        createIcon("Save as", "images/save_as.svg") {
 | 
			
		||||
                            if (saveAs(config)) {
 | 
			
		||||
                                saveAvailableState = true
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                )
 | 
			
		||||
                Column(Modifier.padding(8.dp)) {
 | 
			
		||||
                    projectTypeView.init()
 | 
			
		||||
                    Divider()
 | 
			
		||||
                    licensesView.init()
 | 
			
		||||
                    Divider()
 | 
			
		||||
                    mavenInfoView.init()
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,95 +0,0 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.desktop.views
 | 
			
		||||
 | 
			
		||||
import androidx.compose.foundation.clickable
 | 
			
		||||
import androidx.compose.foundation.layout.*
 | 
			
		||||
import androidx.compose.material.Button
 | 
			
		||||
import androidx.compose.material.Divider
 | 
			
		||||
import androidx.compose.runtime.*
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.compose.ui.unit.dp
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.models.License
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.models.getLicenses
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.desktop.utils.*
 | 
			
		||||
import io.ktor.client.HttpClient
 | 
			
		||||
import kotlinx.coroutines.*
 | 
			
		||||
 | 
			
		||||
private class LicenseState(
 | 
			
		||||
    id: String = "",
 | 
			
		||||
    title: String = "",
 | 
			
		||||
    url: String? = null
 | 
			
		||||
) {
 | 
			
		||||
    var id: String by mutableStateOf(id)
 | 
			
		||||
    var title: String by mutableStateOf(title)
 | 
			
		||||
    var url: String? by mutableStateOf(url)
 | 
			
		||||
 | 
			
		||||
    fun toLicense() = License(id, title, url)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
private fun License.toLicenseState() = LicenseState(id, title, url)
 | 
			
		||||
 | 
			
		||||
class LicensesView: VerticalView("Licenses") {
 | 
			
		||||
    private var licensesListState = mutableStateListOf<LicenseState>()
 | 
			
		||||
    var licenses: List<License>
 | 
			
		||||
        get() = licensesListState.map { it.toLicense() }
 | 
			
		||||
        set(value) {
 | 
			
		||||
            licensesListState.clear()
 | 
			
		||||
            licensesListState.addAll(value.map { it.toLicenseState() })
 | 
			
		||||
        }
 | 
			
		||||
    private val availableLicensesState = mutableStateListOf<License>()
 | 
			
		||||
    private val licensesOffersToShow = mutableStateListOf<License>()
 | 
			
		||||
    private var licenseSearchFilter by mutableStateOf("")
 | 
			
		||||
 | 
			
		||||
    init {
 | 
			
		||||
        CoroutineScope(Dispatchers.Default).launch {
 | 
			
		||||
            val client = HttpClient()
 | 
			
		||||
            availableLicensesState.addAll(client.getLicenses().values)
 | 
			
		||||
            client.close()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override val content: @Composable ColumnScope.() -> Unit = {
 | 
			
		||||
        CommonTextField(licenseSearchFilter, "Search filter") { filterText ->
 | 
			
		||||
            licenseSearchFilter = filterText
 | 
			
		||||
            licensesOffersToShow.clear()
 | 
			
		||||
            if (licenseSearchFilter.isNotEmpty()) {
 | 
			
		||||
                licensesOffersToShow.addAll(
 | 
			
		||||
                    availableLicensesState.filter { filterText.all { symbol -> symbol.lowercaseChar() in it.title } }
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        Column {
 | 
			
		||||
            licensesOffersToShow.forEach {
 | 
			
		||||
                Column(Modifier.padding(16.dp, 8.dp, 8.dp, 8.dp)) {
 | 
			
		||||
                    CommonText(it.title, Modifier.clickable {
 | 
			
		||||
                        licensesListState.add(it.toLicenseState())
 | 
			
		||||
                        licenseSearchFilter = ""
 | 
			
		||||
                        licensesOffersToShow.clear()
 | 
			
		||||
                    })
 | 
			
		||||
                    Divider()
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        Button({ licensesListState.add(LicenseState()) }, Modifier.padding(8.dp)) {
 | 
			
		||||
            CommonText("Add empty license")
 | 
			
		||||
        }
 | 
			
		||||
        licensesListState.forEach { license ->
 | 
			
		||||
            Column(Modifier.padding(8.dp)) {
 | 
			
		||||
                CommonTextField(
 | 
			
		||||
                    license.id,
 | 
			
		||||
                    "License ID"
 | 
			
		||||
                ) { license.id = it }
 | 
			
		||||
                CommonTextField(
 | 
			
		||||
                    license.title,
 | 
			
		||||
                    "License title"
 | 
			
		||||
                ) { license.title = it }
 | 
			
		||||
                CommonTextField(
 | 
			
		||||
                    license.url ?: "",
 | 
			
		||||
                    "License URL"
 | 
			
		||||
                ) { license.url = it }
 | 
			
		||||
                Button({ licensesListState.remove(license) }, Modifier.padding(8.dp)) {
 | 
			
		||||
                    CommonText("Remove")
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,35 +0,0 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.desktop.views
 | 
			
		||||
 | 
			
		||||
import androidx.compose.foundation.layout.*
 | 
			
		||||
import androidx.compose.material.Button
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.runtime.mutableStateListOf
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.compose.ui.unit.dp
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.desktop.utils.CommonText
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.desktop.utils.VerticalView
 | 
			
		||||
 | 
			
		||||
abstract class ListView<T>(title: String) : VerticalView(title) {
 | 
			
		||||
    protected val itemsList = mutableStateListOf<T>()
 | 
			
		||||
 | 
			
		||||
    protected open val addItemText: String = "Add"
 | 
			
		||||
    protected open val removeItemText: String = "Remove"
 | 
			
		||||
 | 
			
		||||
    protected abstract fun createItem(): T
 | 
			
		||||
    @Composable
 | 
			
		||||
    protected abstract fun buildView(item: T)
 | 
			
		||||
 | 
			
		||||
    override val content: @Composable ColumnScope.() -> Unit = {
 | 
			
		||||
        Button({ itemsList.add(createItem()) }) {
 | 
			
		||||
            CommonText(addItemText)
 | 
			
		||||
        }
 | 
			
		||||
        itemsList.forEach { item ->
 | 
			
		||||
            Column(Modifier.padding(8.dp)) {
 | 
			
		||||
                buildView(item)
 | 
			
		||||
                Button({ itemsList.remove(item) }, Modifier.padding(8.dp)) {
 | 
			
		||||
                    CommonText(removeItemText)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,104 +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.Alignment
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.compose.ui.layout.VerticalAlignmentLine
 | 
			
		||||
import androidx.compose.ui.unit.dp
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.models.*
 | 
			
		||||
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 gpgSignProperty by mutableStateOf<GpgSigning>(GpgSigning.Disabled)
 | 
			
		||||
    private var publishToMavenCentralProperty by mutableStateOf(false)
 | 
			
		||||
    private val developersView = DevelopersView()
 | 
			
		||||
    private 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 }
 | 
			
		||||
//            developersView.developers = value.developers
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    @Composable
 | 
			
		||||
    private fun addGpgSigningButton(gpgSigning: GpgSigning) {
 | 
			
		||||
        if (gpgSignProperty == gpgSigning) {
 | 
			
		||||
            Button({}, Modifier.padding(8.dp)) {
 | 
			
		||||
                Text(gpgSigning.name)
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            OutlinedButton(
 | 
			
		||||
                {
 | 
			
		||||
                    gpgSignProperty = gpgSigning
 | 
			
		||||
                },
 | 
			
		||||
                Modifier.padding(8.dp)
 | 
			
		||||
            ) {
 | 
			
		||||
                Text(gpgSigning.name)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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 }
 | 
			
		||||
 | 
			
		||||
        Row(verticalAlignment = Alignment.CenterVertically) {
 | 
			
		||||
            Text("Gpg Signing: ")
 | 
			
		||||
            addGpgSigningButton(GpgSigning.Disabled)
 | 
			
		||||
            addGpgSigningButton(GpgSigning.Optional)
 | 
			
		||||
            addGpgSigningButton(GpgSigning.Enabled)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        SwitchWithLabel(
 | 
			
		||||
            "Include publication to MavenCentral",
 | 
			
		||||
            publishToMavenCentralProperty,
 | 
			
		||||
            placeSwitchAtTheStart = true
 | 
			
		||||
        ) { publishToMavenCentralProperty = it }
 | 
			
		||||
        developersView.init()
 | 
			
		||||
        repositoriesView.init()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,40 +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.Alignment
 | 
			
		||||
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") {
 | 
			
		||||
    var projectType by mutableStateOf<ProjectType>(MultiplatformProjectType)
 | 
			
		||||
 | 
			
		||||
    @Composable
 | 
			
		||||
    private fun addProjectTypeButton(newProjectType: ProjectType) {
 | 
			
		||||
        if (projectType == newProjectType) {
 | 
			
		||||
            Button({}, Modifier.padding(8.dp)) {
 | 
			
		||||
                Text(newProjectType.name)
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            OutlinedButton(
 | 
			
		||||
                {
 | 
			
		||||
                    projectType = newProjectType
 | 
			
		||||
                },
 | 
			
		||||
                Modifier.padding(8.dp)
 | 
			
		||||
            ) {
 | 
			
		||||
                Text(newProjectType.name)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override val content: @Composable ColumnScope.() -> Unit = {
 | 
			
		||||
        Row(verticalAlignment = Alignment.CenterVertically) {
 | 
			
		||||
            addProjectTypeButton(MultiplatformProjectType)
 | 
			
		||||
            addProjectTypeButton(JVMProjectType)
 | 
			
		||||
            addProjectTypeButton(JSProjectType)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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.CommonTextField
 | 
			
		||||
 | 
			
		||||
class RepositoryState(
 | 
			
		||||
    name: String = "",
 | 
			
		||||
    url: String = ""
 | 
			
		||||
) {
 | 
			
		||||
    var name: String by mutableStateOf(name)
 | 
			
		||||
    var url: String by mutableStateOf(url)
 | 
			
		||||
 | 
			
		||||
    fun toRepository() = MavenPublishingRepository(name, url)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
private fun MavenPublishingRepository.toRepositoryState() = RepositoryState(name, url)
 | 
			
		||||
 | 
			
		||||
class RepositoriesView : ListView<RepositoryState>("Repositories info") {
 | 
			
		||||
    var repositories: List<MavenPublishingRepository>
 | 
			
		||||
        get() = itemsList.map { it.toRepository() }
 | 
			
		||||
        set(value) {
 | 
			
		||||
            itemsList.clear()
 | 
			
		||||
            itemsList.addAll(
 | 
			
		||||
                value.map { it.toRepositoryState() }
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    override val addItemText: String = "Add repository"
 | 
			
		||||
    override val removeItemText: String = "Remove repository"
 | 
			
		||||
 | 
			
		||||
    override fun createItem(): RepositoryState = RepositoryState()
 | 
			
		||||
    @Composable
 | 
			
		||||
    override fun buildView(item: RepositoryState) {
 | 
			
		||||
        CommonTextField(
 | 
			
		||||
            item.name,
 | 
			
		||||
            "Repository name"
 | 
			
		||||
        ) { item.name = it }
 | 
			
		||||
        CommonTextField(
 | 
			
		||||
            item.url,
 | 
			
		||||
            "Repository url"
 | 
			
		||||
        ) { item.url = it }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -16,7 +16,6 @@ allprojects {
 | 
			
		||||
        mppProjectWithSerializationPresetPath = "${rootProject.projectDir.absolutePath}/mppProjectWithSerialization.gradle"
 | 
			
		||||
        mppJavaProjectPresetPath = "${rootProject.projectDir.absolutePath}/mppJavaProject.gradle"
 | 
			
		||||
        mppJsProjectPresetPath = "${rootProject.projectDir.absolutePath}/mppJsProject.gradle"
 | 
			
		||||
        mppAndroidProjectPresetPath = "${rootProject.projectDir.absolutePath}/mppAndroidProject.gradle"
 | 
			
		||||
 | 
			
		||||
        defaultAndroidSettingsPresetPath = "${rootProject.projectDir.absolutePath}/defaultAndroidSettings.gradle"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -3,30 +3,18 @@ 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.6.10
 | 
			
		||||
kotlin_coroutines_version=1.6.0
 | 
			
		||||
kotlin_serialisation_core_version=1.3.2
 | 
			
		||||
ktor_version=1.6.7
 | 
			
		||||
micro_utils_version=0.9.0
 | 
			
		||||
kotlin_version=1.7.20
 | 
			
		||||
kotlin_coroutines_version=1.6.4
 | 
			
		||||
kotlin_serialisation_core_version=1.4.1
 | 
			
		||||
ktor_version=2.1.3
 | 
			
		||||
micro_utils_version=0.14.2
 | 
			
		||||
 | 
			
		||||
compose_version=1.0.1
 | 
			
		||||
 | 
			
		||||
# ANDROID
 | 
			
		||||
 | 
			
		||||
android_minSdkVersion=21
 | 
			
		||||
android_compileSdkVersion=32
 | 
			
		||||
android_buildToolsVersion=32.0.0
 | 
			
		||||
dexcount_version=3.0.1
 | 
			
		||||
junit_version=4.12
 | 
			
		||||
test_ext_junit_version=1.1.2
 | 
			
		||||
espresso_core=3.3.0
 | 
			
		||||
compose_version=1.2.1
 | 
			
		||||
 | 
			
		||||
# Dokka
 | 
			
		||||
 | 
			
		||||
dokka_version=1.6.0
 | 
			
		||||
dokka_version=1.7.20
 | 
			
		||||
 | 
			
		||||
# Project data
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										45
									
								
								gradle/libs.versions.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,45 @@
 | 
			
		||||
[versions]
 | 
			
		||||
 | 
			
		||||
kt = "1.7.20"
 | 
			
		||||
kt-serialization = "1.4.1"
 | 
			
		||||
kt-coroutines = "1.6.4"
 | 
			
		||||
 | 
			
		||||
jb-compose = "1.2.1"
 | 
			
		||||
jb-dokka = "1.7.20"
 | 
			
		||||
microutils = "0.14.2"
 | 
			
		||||
kjsuikit = "0.4.1"
 | 
			
		||||
 | 
			
		||||
ktor = "2.1.3"
 | 
			
		||||
 | 
			
		||||
gh-release = "2.4.1"
 | 
			
		||||
 | 
			
		||||
[libraries]
 | 
			
		||||
 | 
			
		||||
kt-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kt" }
 | 
			
		||||
 | 
			
		||||
kt-serialization = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kt-serialization" }
 | 
			
		||||
 | 
			
		||||
kt-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kt-coroutines" }
 | 
			
		||||
 | 
			
		||||
ktor-client = { module = "io.ktor:ktor-client-core", version.ref = "ktor" }
 | 
			
		||||
ktor-client-cio = { module = "io.ktor:ktor-client-cio", version.ref = "ktor" }
 | 
			
		||||
ktor-client-js = { module = "io.ktor:ktor-client-js", version.ref = "ktor" }
 | 
			
		||||
 | 
			
		||||
microutils-common = { module = "dev.inmo:micro_utils.common", version.ref = "microutils" }
 | 
			
		||||
microutils-coroutines = { module = "dev.inmo:micro_utils.coroutines", version.ref = "microutils" }
 | 
			
		||||
 | 
			
		||||
jsuikit = { module = "dev.inmo:kjsuikit", version.ref = "kjsuikit" }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
kt-test-js = { module = "org.jetbrains.kotlin:kotlin-test-js", version.ref = "kt" }
 | 
			
		||||
kt-test-junit = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kt" }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
buildscript-kt-gradle = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kt" }
 | 
			
		||||
buildscript-kt-serialization = { module = "org.jetbrains.kotlin:kotlin-serialization", version.ref = "kt" }
 | 
			
		||||
buildscript-jb-dokka = { module = "org.jetbrains.dokka:dokka-gradle-plugin", version.ref = "jb-dokka" }
 | 
			
		||||
buildscript-gh-release = { module = "com.github.breadmoirai:github-release", version.ref = "gh-release" }
 | 
			
		||||
 | 
			
		||||
[plugins]
 | 
			
		||||
 | 
			
		||||
jb-compose = { id = "org.jetbrains.compose", version.ref = "jb-compose" }
 | 
			
		||||
							
								
								
									
										2
									
								
								gradle/wrapper/gradle-wrapper.properties
									
									
									
									
										vendored
									
									
								
							
							
						
						@@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
 | 
			
		||||
distributionPath=wrapper/dists
 | 
			
		||||
zipStoreBase=GRADLE_USER_HOME
 | 
			
		||||
zipStorePath=wrapper/dists
 | 
			
		||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
 | 
			
		||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
 | 
			
		||||
 
 | 
			
		||||
@@ -4,9 +4,7 @@ project.group = "$group"
 | 
			
		||||
// apply from: "$publishGradlePath"
 | 
			
		||||
 | 
			
		||||
kotlin {
 | 
			
		||||
    jvm {
 | 
			
		||||
        compilations.main.kotlinOptions.useIR = true
 | 
			
		||||
    }
 | 
			
		||||
    jvm()
 | 
			
		||||
 | 
			
		||||
    sourceSets {
 | 
			
		||||
        commonMain {
 | 
			
		||||
 
 | 
			
		||||
@@ -5,10 +5,8 @@ project.group = "$group"
 | 
			
		||||
 | 
			
		||||
kotlin {
 | 
			
		||||
    js (IR) {
 | 
			
		||||
        browser {
 | 
			
		||||
            binaries.executable()
 | 
			
		||||
        }
 | 
			
		||||
        nodejs()
 | 
			
		||||
        browser()
 | 
			
		||||
        binaries.executable()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    sourceSets {
 | 
			
		||||
 
 | 
			
		||||
@@ -4,16 +4,11 @@ project.group = "$group"
 | 
			
		||||
// apply from: "$publishGradlePath"
 | 
			
		||||
 | 
			
		||||
kotlin {
 | 
			
		||||
    jvm {
 | 
			
		||||
        compilations.main.kotlinOptions.useIR = true
 | 
			
		||||
    }
 | 
			
		||||
    jvm()
 | 
			
		||||
    js (IR) {
 | 
			
		||||
        browser()
 | 
			
		||||
        nodejs()
 | 
			
		||||
    }
 | 
			
		||||
    android {
 | 
			
		||||
        publishAllLibraryVariants()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    sourceSets {
 | 
			
		||||
        commonMain {
 | 
			
		||||
@@ -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"
 | 
			
		||||
 
 | 
			
		||||
@@ -9,8 +9,8 @@ rootProject.name = 'kmppscriptbuilder'
 | 
			
		||||
 | 
			
		||||
String[] includes = [
 | 
			
		||||
        ":core",
 | 
			
		||||
        ":desktop",
 | 
			
		||||
        ":web"
 | 
			
		||||
//        ":desktop",
 | 
			
		||||
//        ":web"
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,17 +0,0 @@
 | 
			
		||||
plugins {
 | 
			
		||||
    id "org.jetbrains.kotlin.multiplatform"
 | 
			
		||||
    id "org.jetbrains.kotlin.plugin.serialization"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
apply from: "$mppJsProjectPresetPath"
 | 
			
		||||
 | 
			
		||||
kotlin {
 | 
			
		||||
    sourceSets {
 | 
			
		||||
        commonMain {
 | 
			
		||||
            dependencies {
 | 
			
		||||
                implementation project(":kmppscriptbuilder.core")
 | 
			
		||||
                implementation "dev.inmo:micro_utils.common:$micro_utils_version"
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,82 +0,0 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.web
 | 
			
		||||
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.models.Config
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.utils.serialFormat
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.web.views.*
 | 
			
		||||
import kotlinx.browser.document
 | 
			
		||||
import kotlinx.dom.appendElement
 | 
			
		||||
import org.w3c.dom.*
 | 
			
		||||
import org.w3c.dom.url.URL
 | 
			
		||||
import org.w3c.files.*
 | 
			
		||||
 | 
			
		||||
fun saveFile(content: String, filename: String) {
 | 
			
		||||
    val a = document.body!!.appendElement("a") {
 | 
			
		||||
        setAttribute("style", "visibility:hidden; display: none")
 | 
			
		||||
    } as HTMLAnchorElement
 | 
			
		||||
    val blob = Blob(arrayOf(content), BlobPropertyBag(
 | 
			
		||||
        "application/*;charset=utf-8"
 | 
			
		||||
    ))
 | 
			
		||||
    val url = URL.createObjectURL(blob)
 | 
			
		||||
    a.href = url
 | 
			
		||||
    a.download = filename
 | 
			
		||||
    a.click()
 | 
			
		||||
    URL.revokeObjectURL(url)
 | 
			
		||||
    a.remove()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fun main() {
 | 
			
		||||
    document.addEventListener(
 | 
			
		||||
        "DOMContentLoaded",
 | 
			
		||||
        {
 | 
			
		||||
            val builderView = BuilderView()
 | 
			
		||||
 | 
			
		||||
            (document.getElementById("openConfig") as HTMLElement).onclick = {
 | 
			
		||||
                val targetInput = document.body!!.appendElement("input") {
 | 
			
		||||
                    setAttribute("style", "visibility:hidden; display: none")
 | 
			
		||||
                } as HTMLInputElement
 | 
			
		||||
                targetInput.type = "file"
 | 
			
		||||
                targetInput.onchange = {
 | 
			
		||||
                    targetInput.files ?.also { files ->
 | 
			
		||||
                        for (i in (0 until files.length) ) {
 | 
			
		||||
                            files[i] ?.also { file ->
 | 
			
		||||
                                val reader = FileReader()
 | 
			
		||||
 | 
			
		||||
                                reader.onload = {
 | 
			
		||||
                                    val content = it.target.asDynamic().result as String
 | 
			
		||||
                                    builderView.config = serialFormat.decodeFromString(Config.serializer(), content)
 | 
			
		||||
                                    false
 | 
			
		||||
                                }
 | 
			
		||||
 | 
			
		||||
                                reader.readAsText(file)
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                targetInput.click()
 | 
			
		||||
                targetInput.remove()
 | 
			
		||||
                false
 | 
			
		||||
            }
 | 
			
		||||
            (document.getElementById("saveConfig") as HTMLElement).onclick = {
 | 
			
		||||
                val filename = "publish.kpsb"
 | 
			
		||||
                val content = serialFormat.encodeToString(Config.serializer(), builderView.config)
 | 
			
		||||
 | 
			
		||||
                saveFile(content, filename)
 | 
			
		||||
 | 
			
		||||
                false
 | 
			
		||||
            }
 | 
			
		||||
            (document.getElementById("exportScript") as HTMLElement).onclick = {
 | 
			
		||||
                val filename = "publish.gradle"
 | 
			
		||||
 | 
			
		||||
                val content = builderView.config.run {
 | 
			
		||||
                    type.buildMavenGradleConfig(
 | 
			
		||||
                        mavenConfig,
 | 
			
		||||
                        licenses
 | 
			
		||||
                    )
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                saveFile(content, filename)
 | 
			
		||||
                false
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
@@ -1,13 +0,0 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.web.utils
 | 
			
		||||
 | 
			
		||||
import org.w3c.dom.HTMLElement
 | 
			
		||||
 | 
			
		||||
var HTMLElement.ukActive: Boolean
 | 
			
		||||
    get() = classList.contains("uk-active")
 | 
			
		||||
    set(value) {
 | 
			
		||||
        if (value) {
 | 
			
		||||
            classList.add("uk-active")
 | 
			
		||||
        } else {
 | 
			
		||||
            classList.remove("uk-active")
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -1,10 +0,0 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.web.utils
 | 
			
		||||
 | 
			
		||||
import kotlinx.browser.document
 | 
			
		||||
 | 
			
		||||
inline fun <R> keepScrolling(crossinline block: () -> R): R = document.body ?.let {
 | 
			
		||||
    val (x, y) = (it.scrollLeft to it.scrollTop)
 | 
			
		||||
    return block().also { _ ->
 | 
			
		||||
        it.scrollTo(x, y)
 | 
			
		||||
    }
 | 
			
		||||
} ?: block()
 | 
			
		||||
@@ -1,23 +0,0 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.web.views
 | 
			
		||||
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.models.Config
 | 
			
		||||
import kotlinx.browser.document
 | 
			
		||||
import org.w3c.dom.HTMLElement
 | 
			
		||||
 | 
			
		||||
class BuilderView : View {
 | 
			
		||||
    private val projectTypeView = ProjectTypeView()
 | 
			
		||||
    private val licensesView = LicensesView(document.getElementById("licensesListDiv") as HTMLElement)
 | 
			
		||||
    private val mavenInfoTypeView = MavenProjectInfoView()
 | 
			
		||||
 | 
			
		||||
    var config: Config
 | 
			
		||||
        get() = Config(
 | 
			
		||||
            licensesView.licenses,
 | 
			
		||||
            mavenInfoTypeView.mavenConfig,
 | 
			
		||||
            projectTypeView.projectType
 | 
			
		||||
        )
 | 
			
		||||
        set(value) {
 | 
			
		||||
            licensesView.licenses = value.licenses
 | 
			
		||||
            mavenInfoTypeView.mavenConfig = value.mavenConfig
 | 
			
		||||
            projectTypeView.projectType = value.type
 | 
			
		||||
        }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,35 +0,0 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.web.views
 | 
			
		||||
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.models.Developer
 | 
			
		||||
import org.w3c.dom.*
 | 
			
		||||
 | 
			
		||||
class DevelopersView(rootElement: HTMLElement) : MutableListView<Developer>(rootElement, "Add developer", "Remove developer") {
 | 
			
		||||
    private val HTMLElement.usernameElement: HTMLInputElement
 | 
			
		||||
        get() = getElementsByTagName("input")[0] as HTMLInputElement
 | 
			
		||||
    private val HTMLElement.nameElement: HTMLInputElement
 | 
			
		||||
        get() = getElementsByTagName("input")[1] as HTMLInputElement
 | 
			
		||||
    private val HTMLElement.emailElement: HTMLInputElement
 | 
			
		||||
        get() = getElementsByTagName("input")[2] as HTMLInputElement
 | 
			
		||||
 | 
			
		||||
    var developers: List<Developer>
 | 
			
		||||
        get() = elements.map {
 | 
			
		||||
            Developer(it.usernameElement.value, it.nameElement.value, it.emailElement.value)
 | 
			
		||||
        }
 | 
			
		||||
        set(value) {
 | 
			
		||||
            data = value
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    override fun createPlainObject(): Developer = Developer("", "", "")
 | 
			
		||||
 | 
			
		||||
    override fun HTMLElement.addContentBeforeRemoveButton(value: Developer) {
 | 
			
		||||
        createTextField("Developer ID", "Developer username").value = value.id
 | 
			
		||||
        createTextField("Developer name", "").value = value.name
 | 
			
		||||
        createTextField("Developer E-Mail", "").value = value.eMail
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun HTMLElement.updateElement(from: Developer, to: Developer) {
 | 
			
		||||
        usernameElement.value = to.id
 | 
			
		||||
        nameElement.value = to.name
 | 
			
		||||
        emailElement.value = to.eMail
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,113 +0,0 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.web.views
 | 
			
		||||
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.models.License
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.models.getLicenses
 | 
			
		||||
import dev.inmo.micro_utils.coroutines.safeActor
 | 
			
		||||
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
 | 
			
		||||
import io.ktor.client.HttpClient
 | 
			
		||||
import kotlinx.coroutines.*
 | 
			
		||||
import kotlinx.coroutines.channels.Channel
 | 
			
		||||
import kotlinx.coroutines.channels.SendChannel
 | 
			
		||||
import kotlinx.coroutines.flow.consumeAsFlow
 | 
			
		||||
import kotlinx.coroutines.flow.debounce
 | 
			
		||||
import kotlinx.dom.appendElement
 | 
			
		||||
import org.w3c.dom.*
 | 
			
		||||
 | 
			
		||||
class LicensesView(
 | 
			
		||||
    rootElement: HTMLElement,
 | 
			
		||||
    client: HttpClient = HttpClient(),
 | 
			
		||||
    scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
 | 
			
		||||
) : MutableListView<License>(rootElement, "Add empty license", "Remove license") {
 | 
			
		||||
    private val HTMLElement.idElement: HTMLInputElement
 | 
			
		||||
        get() = getElementsByTagName("input")[0] as HTMLInputElement
 | 
			
		||||
    private val HTMLElement.titleElement: HTMLInputElement
 | 
			
		||||
        get() = getElementsByTagName("input")[1] as HTMLInputElement
 | 
			
		||||
    private val HTMLElement.urlElement: HTMLInputElement
 | 
			
		||||
        get() = getElementsByTagName("input")[2] as HTMLInputElement
 | 
			
		||||
 | 
			
		||||
    private class LicenseOfferList(
 | 
			
		||||
        rootElement: HTMLElement,
 | 
			
		||||
        private val licensesView: LicensesView,
 | 
			
		||||
        client: HttpClient,
 | 
			
		||||
        scope: CoroutineScope
 | 
			
		||||
    ) : ListView<License>(rootElement, useSimpleDiffStrategy = true) {
 | 
			
		||||
        private var licensesTemplates: List<License> = emptyList()
 | 
			
		||||
 | 
			
		||||
        init {
 | 
			
		||||
            scope.launch {
 | 
			
		||||
                licensesTemplates = client.getLicenses().values.toList()
 | 
			
		||||
                changeActor.send(Unit) // update list of searches
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private val changeActor: SendChannel<Unit> = scope.run {
 | 
			
		||||
            val onChangeActor = Channel<Unit>(Channel.CONFLATED)
 | 
			
		||||
            onChangeActor.consumeAsFlow().subscribeSafelyWithoutExceptions(scope) {
 | 
			
		||||
                val lowercased = searchString
 | 
			
		||||
                data = if (lowercased.isEmpty()) {
 | 
			
		||||
                    emptyList()
 | 
			
		||||
                } else {
 | 
			
		||||
                    licensesTemplates.filter {
 | 
			
		||||
                        val lowercasedTitle = it.title.lowercase()
 | 
			
		||||
                        lowercased.all { it in lowercasedTitle }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            onChangeActor
 | 
			
		||||
        }
 | 
			
		||||
        private val searchElement = rootElement.createTextField("Quick add", "Type some license name part to find it").apply {
 | 
			
		||||
            oninput = {
 | 
			
		||||
                changeActor.trySend(Unit)
 | 
			
		||||
                false
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        private var searchString: String
 | 
			
		||||
            get() = searchElement.value.lowercase()
 | 
			
		||||
            set(value) {
 | 
			
		||||
                searchElement.value = value
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        override fun HTMLElement.placeElement(value: License) {
 | 
			
		||||
            createCommonButton(value.title).onclick = {
 | 
			
		||||
                searchString = ""
 | 
			
		||||
                licensesView.licenses += value
 | 
			
		||||
                changeActor.trySend(Unit)
 | 
			
		||||
                false
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        override fun HTMLElement.updateElement(from: License, to: License) {
 | 
			
		||||
            getElementsByTagName("button")[0] ?.remove()
 | 
			
		||||
            placeElement(to)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private val licensesOffersList = LicenseOfferList(
 | 
			
		||||
        rootElement.appendElement("div") { classList.add("uk-padding-small") } as HTMLElement,
 | 
			
		||||
        this,
 | 
			
		||||
        client,
 | 
			
		||||
        scope
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    var licenses: List<License>
 | 
			
		||||
        get() = elements.map {
 | 
			
		||||
            License(it.idElement.value, it.titleElement.value, it.urlElement.value)
 | 
			
		||||
        }
 | 
			
		||||
        set(value) {
 | 
			
		||||
            data = value
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    override fun createPlainObject(): License = License("", "", "")
 | 
			
		||||
 | 
			
		||||
    override fun HTMLElement.addContentBeforeRemoveButton(value: License) {
 | 
			
		||||
        createTextField("License Id", "Short name like \"Apache-2.0\"").value = value.id
 | 
			
		||||
        createTextField("License Title", "Official title of license (like \"Apache Software License 2.0\")").value = value.title
 | 
			
		||||
        createTextField("License URL", "Link to your LICENSE file OR official license file (like \"https://opensource.org/licenses/Apache-2.0\")").value = value.url ?: ""
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun HTMLElement.updateElement(from: License, to: License) {
 | 
			
		||||
        idElement.value = to.id
 | 
			
		||||
        titleElement.value = to.title
 | 
			
		||||
        urlElement.value = to.url ?: ""
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,58 +0,0 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.web.views
 | 
			
		||||
 | 
			
		||||
import dev.inmo.micro_utils.common.calculateStrictDiff
 | 
			
		||||
import kotlinx.dom.appendElement
 | 
			
		||||
import org.w3c.dom.HTMLElement
 | 
			
		||||
 | 
			
		||||
abstract class ListView<T>(
 | 
			
		||||
    protected val rootElement: HTMLElement,
 | 
			
		||||
    useSimpleDiffStrategy: Boolean = false
 | 
			
		||||
) : View {
 | 
			
		||||
    protected val elements = mutableListOf<HTMLElement>()
 | 
			
		||||
    private val diffHandling: (old: List<T>, new: List<T>) -> Unit = if (useSimpleDiffStrategy) {
 | 
			
		||||
        { _, new ->
 | 
			
		||||
            elements.forEach { it.remove() }
 | 
			
		||||
            elements.clear()
 | 
			
		||||
            new.forEach {
 | 
			
		||||
                val element = instantiateElement()
 | 
			
		||||
                elements.add(element)
 | 
			
		||||
                element.placeElement(it)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        {  old, new ->
 | 
			
		||||
            val diff = old.calculateStrictDiff(new)
 | 
			
		||||
            diff.removed.forEach {
 | 
			
		||||
                elements[it.index].remove()
 | 
			
		||||
                elements.removeAt(it.index)
 | 
			
		||||
                println(it.value)
 | 
			
		||||
            }
 | 
			
		||||
            diff.added.forEach {
 | 
			
		||||
                val element = instantiateElement()
 | 
			
		||||
                elements.add(element)
 | 
			
		||||
                element.placeElement(it.value)
 | 
			
		||||
            }
 | 
			
		||||
            diff.replaced.forEach { (old, new) ->
 | 
			
		||||
                val element = elements.getOrNull(old.index) ?.also { it.updateElement(old.value, new.value) }
 | 
			
		||||
                if (element == null) {
 | 
			
		||||
                    val newElement = instantiateElement()
 | 
			
		||||
                    newElement.placeElement(new.value)
 | 
			
		||||
                    elements[new.index] = newElement
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    protected var data: List<T> = emptyList()
 | 
			
		||||
        set(value) {
 | 
			
		||||
            val old = field
 | 
			
		||||
            field = value
 | 
			
		||||
            diffHandling(old, value)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    protected abstract fun HTMLElement.placeElement(value: T)
 | 
			
		||||
    protected abstract fun HTMLElement.updateElement(from: T, to: T)
 | 
			
		||||
 | 
			
		||||
    private fun instantiateElement() = rootElement.appendElement("div") {
 | 
			
		||||
        classList.add("uk-padding-small")
 | 
			
		||||
    } as HTMLElement
 | 
			
		||||
}
 | 
			
		||||
@@ -1,82 +0,0 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.web.views
 | 
			
		||||
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.models.*
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.web.utils.ukActive
 | 
			
		||||
import kotlinx.browser.document
 | 
			
		||||
import org.w3c.dom.HTMLElement
 | 
			
		||||
import org.w3c.dom.HTMLInputElement
 | 
			
		||||
 | 
			
		||||
class MavenProjectInfoView : View {
 | 
			
		||||
    private val nameElement = document.getElementById("projectNameInput") as HTMLInputElement
 | 
			
		||||
    private val descriptionElement = document.getElementById("projectDescriptionInput") as HTMLInputElement
 | 
			
		||||
    private val urlElement = document.getElementById("projectUrlInput") as HTMLInputElement
 | 
			
		||||
    private val vcsUrlElement = document.getElementById("projectVCSUrlInput") as HTMLInputElement
 | 
			
		||||
    private val disableGpgSigningElement = document.getElementById("disableGpgSigning") as HTMLElement
 | 
			
		||||
    private val optionalGpgSigningElement = document.getElementById("optionalGpgSigning") as HTMLElement
 | 
			
		||||
    private val enableGpgSigningElement = document.getElementById("enableGpgSigning") as HTMLElement
 | 
			
		||||
    private val includeMavenCentralElement = document.getElementById("includeMavenCentralTargetRepoToggle") as HTMLInputElement
 | 
			
		||||
    private val developersView = DevelopersView(document.getElementById("developersListDiv") as HTMLElement)
 | 
			
		||||
    private val repositoriesView = RepositoriesView(document.getElementById("repositoriesListDiv") as HTMLElement)
 | 
			
		||||
 | 
			
		||||
    private var gpgSignMode: GpgSigning = GpgSigning.Disabled
 | 
			
		||||
        set(value) {
 | 
			
		||||
            field = value
 | 
			
		||||
            when (value) {
 | 
			
		||||
                GpgSigning.Enabled -> {
 | 
			
		||||
                    enableGpgSigningElement.ukActive = true
 | 
			
		||||
                    disableGpgSigningElement.ukActive = false
 | 
			
		||||
                    optionalGpgSigningElement.ukActive = false
 | 
			
		||||
                }
 | 
			
		||||
                GpgSigning.Optional -> {
 | 
			
		||||
                    enableGpgSigningElement.ukActive = false
 | 
			
		||||
                    disableGpgSigningElement.ukActive = false
 | 
			
		||||
                    optionalGpgSigningElement.ukActive = true
 | 
			
		||||
                }
 | 
			
		||||
                GpgSigning.Disabled -> {
 | 
			
		||||
                    enableGpgSigningElement.ukActive = false
 | 
			
		||||
                    disableGpgSigningElement.ukActive = true
 | 
			
		||||
                    optionalGpgSigningElement.ukActive = false
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    var mavenConfig: MavenConfig
 | 
			
		||||
        get() = MavenConfig(
 | 
			
		||||
            nameElement.value.ifBlank { defaultProjectName },
 | 
			
		||||
            descriptionElement.value.ifBlank { defaultProjectDescription },
 | 
			
		||||
            urlElement.value,
 | 
			
		||||
            vcsUrlElement.value,
 | 
			
		||||
            developersView.developers,
 | 
			
		||||
            repositoriesView.repositories + if (includeMavenCentralElement.checked) {
 | 
			
		||||
                listOf(SonatypeRepository)
 | 
			
		||||
            } else {
 | 
			
		||||
                emptyList()
 | 
			
		||||
            },
 | 
			
		||||
            when {
 | 
			
		||||
                optionalGpgSigningElement.ukActive -> GpgSigning.Optional
 | 
			
		||||
                enableGpgSigningElement.ukActive -> GpgSigning.Enabled
 | 
			
		||||
                else -> GpgSigning.Disabled
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
        set(value) {
 | 
			
		||||
            nameElement.value = value.name
 | 
			
		||||
            descriptionElement.value = value.description
 | 
			
		||||
            urlElement.value = value.url
 | 
			
		||||
            vcsUrlElement.value = value.vcsUrl
 | 
			
		||||
            gpgSignMode = if (value.includeGpgSigning) {
 | 
			
		||||
                GpgSigning.Enabled
 | 
			
		||||
            } else {
 | 
			
		||||
                value.gpgSigning
 | 
			
		||||
            }
 | 
			
		||||
            developersView.developers = value.developers
 | 
			
		||||
            val reposWithoutSonatype = value.repositories.filter { it != SonatypeRepository }
 | 
			
		||||
            includeMavenCentralElement.checked = value.repositories.size != reposWithoutSonatype.size
 | 
			
		||||
            repositoriesView.repositories = reposWithoutSonatype
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    init {
 | 
			
		||||
        enableGpgSigningElement.onclick = { gpgSignMode = GpgSigning.Enabled; Unit }
 | 
			
		||||
        disableGpgSigningElement.onclick = { gpgSignMode = GpgSigning.Disabled; Unit }
 | 
			
		||||
        optionalGpgSigningElement.onclick = { gpgSignMode = GpgSigning.Optional; Unit }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,41 +0,0 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.web.views
 | 
			
		||||
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.web.utils.keepScrolling
 | 
			
		||||
import org.w3c.dom.HTMLElement
 | 
			
		||||
 | 
			
		||||
abstract class MutableListView<T>(
 | 
			
		||||
    rootElement: HTMLElement,
 | 
			
		||||
    addButtonText: String = "Add",
 | 
			
		||||
    private val removeButtonText: String = "Remove"
 | 
			
		||||
) : ListView<T>(rootElement) {
 | 
			
		||||
    init {
 | 
			
		||||
        rootElement.createPrimaryButton(addButtonText).apply {
 | 
			
		||||
            onclick = {
 | 
			
		||||
                keepScrolling {
 | 
			
		||||
                    val newObject = createPlainObject()
 | 
			
		||||
                    data += newObject
 | 
			
		||||
                }
 | 
			
		||||
                false
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected abstract fun createPlainObject(): T
 | 
			
		||||
    protected open fun HTMLElement.addContentBeforeRemoveButton(value: T) {}
 | 
			
		||||
    protected open fun HTMLElement.addContentAfterRemoveButton(value: T) {}
 | 
			
		||||
    final override fun HTMLElement.placeElement(value: T) {
 | 
			
		||||
        addContentBeforeRemoveButton(value)
 | 
			
		||||
        addRemoveButton()
 | 
			
		||||
        addContentAfterRemoveButton(value)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun HTMLElement.addRemoveButton() {
 | 
			
		||||
        val button = createPrimaryButton(removeButtonText)
 | 
			
		||||
        button.onclick = {
 | 
			
		||||
            elements.indexOf(button.parentElement).takeIf { it > -1 } ?.also {
 | 
			
		||||
                data -= data[it]
 | 
			
		||||
            } ?: rootElement.removeChild(this@addRemoveButton)
 | 
			
		||||
            false
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,39 +0,0 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.web.views
 | 
			
		||||
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.models.*
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.web.utils.ukActive
 | 
			
		||||
import kotlinx.browser.document
 | 
			
		||||
import org.w3c.dom.HTMLElement
 | 
			
		||||
 | 
			
		||||
class ProjectTypeView : View {
 | 
			
		||||
    private val mppProjectTypeElement = document.getElementById("mppProjectType") as HTMLElement
 | 
			
		||||
    private val jvmProjectTypeElement = document.getElementById("jvmProjectType") as HTMLElement
 | 
			
		||||
    private val jsProjectTypeElement = document.getElementById("jsProjectType") as HTMLElement
 | 
			
		||||
 | 
			
		||||
    var projectType: ProjectType
 | 
			
		||||
        get() = when {
 | 
			
		||||
            jvmProjectTypeElement.ukActive -> JVMProjectType
 | 
			
		||||
            jsProjectTypeElement.ukActive -> JSProjectType
 | 
			
		||||
            else -> MultiplatformProjectType
 | 
			
		||||
        }
 | 
			
		||||
        set(value) {
 | 
			
		||||
            mppProjectTypeElement.ukActive = value == MultiplatformProjectType
 | 
			
		||||
            jvmProjectTypeElement.ukActive = value == JVMProjectType
 | 
			
		||||
            jsProjectTypeElement.ukActive = value == JSProjectType
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    init {
 | 
			
		||||
        mppProjectTypeElement.onclick = {
 | 
			
		||||
            projectType = MultiplatformProjectType
 | 
			
		||||
            Unit
 | 
			
		||||
        }
 | 
			
		||||
        jvmProjectTypeElement.onclick = {
 | 
			
		||||
            projectType = JVMProjectType
 | 
			
		||||
            Unit
 | 
			
		||||
        }
 | 
			
		||||
        jsProjectTypeElement.onclick = {
 | 
			
		||||
            projectType = JSProjectType
 | 
			
		||||
            Unit
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,31 +0,0 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.web.views
 | 
			
		||||
 | 
			
		||||
import dev.inmo.kmppscriptbuilder.core.models.MavenPublishingRepository
 | 
			
		||||
import org.w3c.dom.*
 | 
			
		||||
 | 
			
		||||
class RepositoriesView(rootElement: HTMLElement) : MutableListView<MavenPublishingRepository>(rootElement, "Add repository", "Remove repository") {
 | 
			
		||||
    private val HTMLElement.nameElement: HTMLInputElement
 | 
			
		||||
        get() = getElementsByTagName("input")[0] as HTMLInputElement
 | 
			
		||||
    private val HTMLElement.urlElement: HTMLInputElement
 | 
			
		||||
        get() = getElementsByTagName("input")[1] as HTMLInputElement
 | 
			
		||||
 | 
			
		||||
    var repositories: List<MavenPublishingRepository>
 | 
			
		||||
        get() = elements.map {
 | 
			
		||||
            MavenPublishingRepository(it.nameElement.value, it.urlElement.value)
 | 
			
		||||
        }
 | 
			
		||||
        set(value) {
 | 
			
		||||
            data = value
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    override fun createPlainObject(): MavenPublishingRepository = MavenPublishingRepository("", "")
 | 
			
		||||
 | 
			
		||||
    override fun HTMLElement.addContentBeforeRemoveButton(value: MavenPublishingRepository) {
 | 
			
		||||
        createTextField("Repository name", "This name will be used to identify repository in grade").value = value.name
 | 
			
		||||
        createTextField("Repository URL", "For example: https://repo.maven.apache.org/maven2/").value = value.url
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun HTMLElement.updateElement(from: MavenPublishingRepository, to: MavenPublishingRepository) {
 | 
			
		||||
        nameElement.value = to.name
 | 
			
		||||
        urlElement.value = to.url
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,3 +0,0 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.web.views
 | 
			
		||||
 | 
			
		||||
interface View
 | 
			
		||||
@@ -1,35 +0,0 @@
 | 
			
		||||
package dev.inmo.kmppscriptbuilder.web.views
 | 
			
		||||
 | 
			
		||||
import kotlinx.dom.appendElement
 | 
			
		||||
import org.w3c.dom.*
 | 
			
		||||
 | 
			
		||||
fun HTMLElement.createTextField(
 | 
			
		||||
    label: String,
 | 
			
		||||
    placeholder: String
 | 
			
		||||
): HTMLInputElement {
 | 
			
		||||
    return appendElement("div") {
 | 
			
		||||
        classList.add("uk-margin", "uk-width-1-1")
 | 
			
		||||
    }.appendElement("label") {
 | 
			
		||||
        classList.add("uk-form-label")
 | 
			
		||||
        innerHTML = label
 | 
			
		||||
    }.run {
 | 
			
		||||
        val input = appendElement("input") {
 | 
			
		||||
            classList.add("uk-input", "uk-width-expand")
 | 
			
		||||
            setAttribute("type", "text")
 | 
			
		||||
            setAttribute("placeholder", placeholder)
 | 
			
		||||
        } as HTMLInputElement
 | 
			
		||||
        input
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fun HTMLElement.createPrimaryButton(text: String): HTMLButtonElement = (appendElement("button") {
 | 
			
		||||
    classList.add("uk-button", "uk-button-primary")
 | 
			
		||||
} as HTMLButtonElement).apply {
 | 
			
		||||
    innerText = text
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fun HTMLElement.createCommonButton(text: String): HTMLButtonElement = (appendElement("button") {
 | 
			
		||||
    classList.add("uk-button", "uk-button-default")
 | 
			
		||||
} as HTMLButtonElement).apply {
 | 
			
		||||
    innerText = text
 | 
			
		||||
}
 | 
			
		||||
@@ -1,85 +0,0 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<html lang="en">
 | 
			
		||||
<head>
 | 
			
		||||
    <meta charset="UTF-8">
 | 
			
		||||
    <title>Kotlin Publication Scripts Builder</title>
 | 
			
		||||
    <!-- UIkit CSS -->
 | 
			
		||||
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/uikit@3.6.17/dist/css/uikit.min.css" />
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
    <nav class="uk-navbar-container" uk-navbar>
 | 
			
		||||
        <div class="uk-navbar-left">
 | 
			
		||||
            <div class="uk-padding-small uk-text-lead">Kotlin Publication Scripts Builder</div>
 | 
			
		||||
            <div class="uk-padding-small"><a href="https://github.com/InsanusMokrassar/KotlinPublicationScriptsBuilder"><img src="https://img.shields.io/github/stars/InsanusMokrassar/KotlinPublicationScriptsBuilder?label=Github&style=plastic"/></a></div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="uk-navbar-right">
 | 
			
		||||
            <ul class="uk-navbar-nav">
 | 
			
		||||
                <li uk-tooltip="title: Open config" id="openConfig"><a href="#"><span uk-icon="icon: pull"></span></a></li><!--Open file-->
 | 
			
		||||
                <li uk-tooltip="title: Save config" id="saveConfig"><a href="#"><span uk-icon="icon: push"></span></a></li><!--Save file-->
 | 
			
		||||
                <li uk-tooltip="title: Export script" id="exportScript"><a href="#"><span uk-icon="icon: upload"></span></a></li><!--Save file-->
 | 
			
		||||
            </ul>
 | 
			
		||||
        </div>
 | 
			
		||||
    </nav>
 | 
			
		||||
    <form class="uk-padding-small">
 | 
			
		||||
        <fieldset class="uk-fieldset">
 | 
			
		||||
            <legend class="uk-legend">Project type</legend>
 | 
			
		||||
            <div class="uk-padding-small">
 | 
			
		||||
                <ul class="uk-subnav uk-subnav-pill">
 | 
			
		||||
                    <li id="mppProjectType" class="uk-active"><a href="#">Multiplatform</a></li>
 | 
			
		||||
                    <li id="jvmProjectType"><a href="#">JVM</a></li>
 | 
			
		||||
                    <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="https://cdn.jsdelivr.net/npm/uikit@3.6.17/dist/js/uikit.min.js"></script>
 | 
			
		||||
    <script src="https://cdn.jsdelivr.net/npm/uikit@3.6.17/dist/js/uikit-icons.min.js"></script>
 | 
			
		||||
    <!-- Internal JS -->
 | 
			
		||||
    <script src="kmppscriptbuilder.web.js"></script>
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||