diff --git a/mirai-console-graphical/build.gradle.kts b/mirai-console-graphical/build.gradle.kts index ff3b538db..f82af1251 100644 --- a/mirai-console-graphical/build.gradle.kts +++ b/mirai-console-graphical/build.gradle.kts @@ -57,7 +57,9 @@ dependencies { api(group = "com.jfoenix", name = "jfoenix", version = "9.0.8") testApi(project(":mirai-console")) + testApi(kotlinx("coroutines-core", Versions.Kotlin.coroutines)) testApi(group = "org.yaml", name = "snakeyaml", version = "1.25") + testApi("net.mamoe:mirai-core-jvm:${Versions.Mirai.core}") } tasks.withType { diff --git a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/controller/MiraiGraphicalUIController.kt b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/controller/MiraiGraphicalUIController.kt index 41ed4e643..1f3b27167 100644 --- a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/controller/MiraiGraphicalUIController.kt +++ b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/controller/MiraiGraphicalUIController.kt @@ -125,6 +125,29 @@ class MiraiGraphicalUIController : Controller(), MiraiConsoleUI { } } + fun checkLatest(plugin: PluginModel) { + pluginList.forEach { + if (it.name == plugin.name && it.author == plugin.author) { + if (plugin.version > it.version) { + it.latest = false + return + } + } + } + } + + /** + * return `true` when command is ambiguous + */ + fun checkAmbiguous(plugin: PluginModel) : Boolean { + plugin.insight?.commands?.forEach { name -> + CommandManager.commands.forEach { + if (name == it.name) return true + } + } ?: return false + return false + } + } class GraphicalLoginSolver : LoginSolver() { diff --git a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/model/PluginModel.kt b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/model/PluginModel.kt index 763201b07..a6879cbab 100644 --- a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/model/PluginModel.kt +++ b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/model/PluginModel.kt @@ -3,6 +3,7 @@ package net.mamoe.mirai.console.graphical.model import com.jfoenix.controls.datamodels.treetable.RecursiveTreeObject import javafx.beans.property.SimpleBooleanProperty import javafx.beans.property.SimpleStringProperty +import net.mamoe.mirai.console.center.PluginCenter import net.mamoe.mirai.console.plugins.PluginDescription import tornadofx.getValue import tornadofx.setValue @@ -11,7 +12,8 @@ class PluginModel( val name: String, val version: String, val author: String, - val description: String + val description: String, + var insight: PluginCenter.PluginInsight? = null ) : RecursiveTreeObject() { constructor(plugin: PluginDescription) : this(plugin.name, plugin.version, plugin.author, plugin.info) @@ -22,4 +24,7 @@ class PluginModel( val enabledProperty = SimpleBooleanProperty(this, "enabledProperty") var enabled by enabledProperty + + val latestProperty = SimpleBooleanProperty(this, "latestProperty", true) + var latest by latestProperty } \ No newline at end of file diff --git a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/view/PluginsCenterView.kt b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/view/PluginsCenterView.kt new file mode 100644 index 000000000..4ef33ba7b --- /dev/null +++ b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/view/PluginsCenterView.kt @@ -0,0 +1,126 @@ +package net.mamoe.mirai.console.graphical.view + +import com.jfoenix.controls.JFXTreeTableColumn +import javafx.collections.ObservableList +import javafx.geometry.Pos +import javafx.scene.control.TreeTableCell +import kotlinx.coroutines.runBlocking +import net.mamoe.mirai.console.center.CuiPluginCenter +import net.mamoe.mirai.console.graphical.controller.MiraiGraphicalUIController +import net.mamoe.mirai.console.graphical.model.PluginModel +import net.mamoe.mirai.console.graphical.stylesheet.PluginViewStyleSheet +import net.mamoe.mirai.console.graphical.util.jfxButton +import net.mamoe.mirai.console.graphical.util.jfxTreeTableView +import tornadofx.* + +class PluginsCenterView : View() { + + private val controller = find() + private val center = CuiPluginCenter + private val plugins: ObservableList by lazy(::fetch) + + override val root = jfxTreeTableView(plugins) { + + addStylesheet(PluginViewStyleSheet::class) + + isShowRoot = false + columns.addAll( + JFXTreeTableColumn("插件名").apply { + prefWidthProperty().bind(this@jfxTreeTableView.widthProperty().multiply(0.1)) + + setCellValueFactory { + return@setCellValueFactory it.value.value.nameProperty + } + }, + JFXTreeTableColumn("版本").apply { + prefWidthProperty().bind(this@jfxTreeTableView.widthProperty().multiply(0.1)) + + setCellValueFactory { + return@setCellValueFactory it.value.value.versionProperty + } + }, + JFXTreeTableColumn("作者").apply { + prefWidthProperty().bind(this@jfxTreeTableView.widthProperty().multiply(0.1)) + + setCellValueFactory { + return@setCellValueFactory it.value.value.authorProperty + } + }, + JFXTreeTableColumn("介绍").apply { + prefWidthProperty().bind(this@jfxTreeTableView.widthProperty().multiply(0.48)) + + setCellValueFactory { + return@setCellValueFactory it.value.value.descriptionProperty + } + }, + JFXTreeTableColumn("操作").apply { + prefWidthProperty().bind(this@jfxTreeTableView.widthProperty().multiply(0.2)) + + setCellValueFactory { return@setCellValueFactory it.value.valueProperty() } + + setCellFactory { + return@setCellFactory object : TreeTableCell() { + override fun updateItem(item: PluginModel?, empty: Boolean) { + if (item != null && !empty) { + graphic = hbox { + + spacing = 15.0 + alignment = Pos.CENTER + + jfxButton("详情") { + action { detail(item) } + } + + + jfxButton("下载") { + action { download(item) } + } + + } + text = "" + } else { + graphic = null + text = "" + } + } + } + } + } + ) + + } + + private fun fetch(): ObservableList = + runAsync { + val ret = observableListOf() + runBlocking { + var page = 1 + while (true) { + val map = center.fetchPlugin(page++) + if (map.isEmpty()) return@runBlocking + map.forEach { + ret.add( + PluginModel( + it.value.name, + it.value.version, + it.value.author, + it.value.description, + it.value + ) + ) + } + } + } + return@runAsync ret + }.get() + + private fun detail(pluginModel: PluginModel) { + //to show pluginModel.insight + } + + private fun download(pluginModel: PluginModel) { + // controller.checkAmbiguous(pluginModel) + // do nothing + } + +} \ No newline at end of file diff --git a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/view/PrimaryView.kt b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/view/PrimaryView.kt index a50453e12..eb8706205 100644 --- a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/view/PrimaryView.kt +++ b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/view/PrimaryView.kt @@ -120,6 +120,8 @@ class PrimaryView : View() { fixedTab("Plugins").content = find().root + fixedTab("Plugins Center").content = find().root + fixedTab("Settings").content = find().root fixedTab("Login").content = find().root diff --git a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/center/CuiPluginCenter.kt b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/center/CuiPluginCenter.kt index 6478b16a8..7b2ee4873 100644 --- a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/center/CuiPluginCenter.kt +++ b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/center/CuiPluginCenter.kt @@ -1,6 +1,5 @@ package net.mamoe.mirai.console.center -import com.google.gson.Gson import com.google.gson.JsonArray import com.google.gson.JsonObject import com.google.gson.JsonParser @@ -24,20 +23,20 @@ object CuiPluginCenter: PluginCenter{ if(plugins == null){ refresh() } - if(it > plugins!!.size()){ + if(it >= plugins!!.size()){ return@forEach } val info = plugins!![it] with(info.asJsonObject){ map[this.get("name").asString] = PluginCenter.PluginInsight( - this.get("name").asString, - this.get("version").asString, - this.get("core").asString, - this.get("console").asString, - this.get("author").asString, - this.get("contact").asString, - this.get("tags").asJsonArray.map { it.asString }, - this.get("commands").asJsonArray.map { it.asString } + this.get("name")?.asString ?: "", + this.get("version")?.asString ?: "", + this.get("core")?.asString ?: "", + this.get("console")?.asString ?: "", + this.get("author")?.asString ?: "", + this.get("contact")?.asString ?: "", + this.get("tags")?.asJsonArray?.map { it.asString } ?: arrayListOf(), + this.get("commands")?.asJsonArray?.map { it.asString } ?: arrayListOf() ) } }