User: strokkur24 Date: 17 Jan 26 14:18 Revision: 0f4c6aa9f15dedc3316db2000971fc431596a634 Summary: Fetch Paper versions async TeamCity URL: http://ci.mcdev.io:80/viewModification.html?tab=vcsModificationFiles&modId=10394&personal=false Index: src/main/kotlin/creator/custom/types/PaperVersionCreatorProperty.kt =================================================================== --- src/main/kotlin/creator/custom/types/PaperVersionCreatorProperty.kt (revision 1257098164cc9868a3564684bd3cd3e8887715fb) +++ src/main/kotlin/creator/custom/types/PaperVersionCreatorProperty.kt (revision 0f4c6aa9f15dedc3316db2000971fc431596a634) @@ -22,15 +22,23 @@ import com.demonwav.mcdev.creator.custom.CreatorContext import com.demonwav.mcdev.creator.custom.TemplatePropertyDescriptor +import com.demonwav.mcdev.creator.custom.TemplateValidationReporter +import com.demonwav.mcdev.update.PluginUtil import com.demonwav.mcdev.util.MinecraftVersions import com.demonwav.mcdev.util.SemanticVersion +import com.intellij.ui.ComboboxSpeedSearch +import com.intellij.ui.JBColor import com.intellij.ui.dsl.builder.Panel +import com.intellij.ui.dsl.builder.bindItem +import com.intellij.ui.dsl.builder.bindText +import com.intellij.util.ui.AsyncProcessIcon import io.ktor.client.* import io.ktor.client.request.* import io.ktor.client.statement.* import io.ktor.http.* import kotlinx.coroutines.DelicateCoroutinesApi -import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch import kotlinx.serialization.json.Json import kotlinx.serialization.json.jsonArray import kotlinx.serialization.json.jsonObject @@ -43,36 +51,75 @@ @OptIn(DelicateCoroutinesApi::class) companion object { - val paperVersions: Map? = loadPaperVersions()?.associate { it to it.toString() } + private var paperVersions: List? = null - fun loadPaperVersions(): List? { + suspend fun getPaperVersions(): List { + paperVersions?.let { return it } + val client = HttpClient() - return runBlocking { - val response = client.get("https://fill.papermc.io/v3/projects/paper") + val response = client.get("https://fill.papermc.io/v3/projects/paper", block = { + this.header("User-Agent", "minecraft-dev/${PluginUtil.pluginVersion} (https://github.com/minecraft-dev/MinecraftDev)") + }) - if (response.status.isSuccess()) { - val element = Json.parseToJsonElement(response.bodyAsText()) + if (response.status.isSuccess()) { + val element = Json.parseToJsonElement(response.bodyAsText()) - return@runBlocking element.jsonObject["versions"]?.jsonObject?.values + val result = element.jsonObject["versions"]?.jsonObject?.values - ?.asSequence() - ?.flatMap { it.jsonArray } - ?.map { it.jsonPrimitive.content } - ?.mapNotNull { SemanticVersion.tryParse(it) } - // only release versions - ?.filter { ver -> ver.parts.all { it is SemanticVersion.Companion.VersionPart.ReleasePart } } - // nothing lower than 1.18.2 should be selectable - ?.filter { it >= MinecraftVersions.MC1_18_2 } - ?.toList() - ?.sortedDescending() + ?.asSequence() + ?.flatMap { it.jsonArray } + ?.map { it.jsonPrimitive.content } + ?.mapNotNull { SemanticVersion.tryParse(it) } + // only release versions + ?.filter { ver -> ver.parts.all { it is SemanticVersion.Companion.VersionPart.ReleasePart } } + // nothing lower than 1.18.2 should be selectable + ?.filter { it >= MinecraftVersions.MC1_18_2 } + ?.toList() + ?.sortedDescending() - } else { - return@runBlocking null + + if (result != null) { + paperVersions = result + return result } } + + return emptyList() } } + private val versionsProperty = graph.property>(emptySet()) + private val loadingVersionsProperty = graph.property(true) + private val loadingVersionsStatusProperty = graph.property("") + override fun buildUi(panel: Panel) { - super.buildDropdownMenu(panel, paperVersions) + panel.row(descriptor.translatedLabel) { + val combobox = comboBox(versionsProperty.get()) + .bindItem(graphProperty) + .enabled(descriptor.editable != false) + .also { ComboboxSpeedSearch.installOn(it.component) } + + cell(AsyncProcessIcon(makeStorageKey("progress"))) + .visibleIf(loadingVersionsProperty) + label("").applyToComponent { foreground = JBColor.RED } + .bindText(loadingVersionsStatusProperty) + .visibleIf(loadingVersionsProperty) + + versionsProperty.afterChange { versions -> + combobox.component.removeAllItems() + for (version in versions) { + combobox.component.addItem(version) - } + } + } + }.propertyVisibility() + } + override fun setupProperty(reporter: TemplateValidationReporter) { + super.setupProperty(reporter) + val scope = context.childScope("PaperVersionCreatorProperty") + scope.launch(Dispatchers.Default) { + val result = getPaperVersions() + versionsProperty.set(result.toSet()) + loadingVersionsProperty.set(false) + } + } + class Factory : CreatorPropertyFactory { override fun create( descriptor: TemplatePropertyDescriptor, Index: src/main/kotlin/creator/custom/types/SimpleCreatorProperty.kt =================================================================== --- src/main/kotlin/creator/custom/types/SimpleCreatorProperty.kt (revision 1257098164cc9868a3564684bd3cd3e8887715fb) +++ src/main/kotlin/creator/custom/types/SimpleCreatorProperty.kt (revision 0f4c6aa9f15dedc3316db2000971fc431596a634) @@ -78,41 +78,37 @@ override val graphProperty: GraphProperty by lazy { graph.property(defaultValue) } - protected fun buildDropdownMenu(panel: Panel, options: Map?) { + override fun buildUi(panel: Panel) { + if (isDropdown) { - if (graphProperty.get() !in options!!.keys) { - graphProperty.set(defaultValue) - } + if (graphProperty.get() !in options!!.keys) { + graphProperty.set(defaultValue) + } - panel.row(descriptor.translatedLabel) { - if (descriptor.forceDropdown == true) { - comboBox(options.keys, DropdownAutoRenderer()) - .bindItem(graphProperty) - .enabled(descriptor.editable != false) - .also { - val component = it.component - ComboboxSpeedSearch.installOn(component) - val validation = - BuiltinValidations.isAnyOf(component::getSelectedItem, options.keys, component) - it.validationOnInput(validation) - it.validationOnApply(validation) - } - } else { - segmentedButton(options.keys) { text = options[it] ?: it.toString() } - .bind(graphProperty) - .enabled(descriptor.editable != false) - .maxButtonsCount(4) - .validation { - val message = MCDevBundle("creator.validation.invalid_option") - addInputRule(message) { it.selectedItem !in options.keys } - addApplyRule(message) { it.selectedItem !in options.keys } - } - } - }.propertyVisibility() + panel.row(descriptor.translatedLabel) { + if (descriptor.forceDropdown == true) { + comboBox(options.keys, DropdownAutoRenderer()) + .bindItem(graphProperty) + .enabled(descriptor.editable != false) + .also { + val component = it.component + ComboboxSpeedSearch.installOn(component) + val validation = + BuiltinValidations.isAnyOf(component::getSelectedItem, options.keys, component) + it.validationOnInput(validation) + it.validationOnApply(validation) + } + } else { + segmentedButton(options.keys) { text = options[it] ?: it.toString() } + .bind(graphProperty) + .enabled(descriptor.editable != false) + .maxButtonsCount(4) + .validation { + val message = MCDevBundle("creator.validation.invalid_option") + addInputRule(message) { it.selectedItem !in options.keys } + addApplyRule(message) { it.selectedItem !in options.keys } + } + } + }.propertyVisibility() - } - - override fun buildUi(panel: Panel) { - if (isDropdown) { - buildDropdownMenu(panel, options) } else { buildSimpleUi(panel) }