From 0b67226cb72b82ac0f48d94ff7084985ead2c31f Mon Sep 17 00:00:00 2001
From: ryoii <ryoii@foxmail.com>
Date: Mon, 30 Mar 2020 19:01:05 +0800
Subject: [PATCH 1/6] Fix: exit problem

---
 .../kotlin/net/mamoe/mirai/console/graphical/MiraiGraphical.kt  | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/MiraiGraphical.kt b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/MiraiGraphical.kt
index 5c2f48555..b12f55ce2 100644
--- a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/MiraiGraphical.kt
+++ b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/MiraiGraphical.kt
@@ -15,6 +15,7 @@ import net.mamoe.mirai.console.graphical.stylesheet.PrimaryStyleSheet
 import net.mamoe.mirai.console.graphical.view.Decorator
 import tornadofx.App
 import tornadofx.find
+import kotlin.system.exitProcess
 
 //object MiraiGraphicalLoader {
 //    @JvmStatic
@@ -33,5 +34,6 @@ class MiraiGraphicalUI : App(Decorator::class, PrimaryStyleSheet::class) {
     override fun stop() {
         super.stop()
         MiraiConsole.stop()
+        exitProcess(0)
     }
 }

From baddc1117b23a052c000e1225af2d0dda5ebb91e Mon Sep 17 00:00:00 2001
From: ryoii <ryoii@foxmail.com>
Date: Mon, 30 Mar 2020 19:11:23 +0800
Subject: [PATCH 2/6] Fix: multi bot list cell

---
 .../controller/MiraiGraphicalUIController.kt          | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

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 30bd9cb2e..793db0a96 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
@@ -7,6 +7,7 @@ import javafx.stage.StageStyle
 import kotlinx.coroutines.delay
 import net.mamoe.mirai.Bot
 import net.mamoe.mirai.console.command.CommandManager
+import net.mamoe.mirai.console.command.CommandManager.runCommand
 import net.mamoe.mirai.console.command.ConsoleCommandSender
 import net.mamoe.mirai.console.graphical.model.*
 import net.mamoe.mirai.console.graphical.view.dialog.InputDialog
@@ -41,7 +42,7 @@ class MiraiGraphicalUIController : Controller(), MiraiConsoleUI {
         CommandManager.runCommand(ConsoleCommandSender, "/login $qq $psd")
     }
 
-    fun sendCommand(command: String) = CommandManager.runCommand(ConsoleCommandSender, command)
+    fun sendCommand(command: String) = runCommand(ConsoleCommandSender, command)
 
     override fun pushLog(identity: Long, message: String) = Platform.runLater {
         this.pushLog(LogPriority.INFO, "", identity, message)
@@ -65,9 +66,11 @@ class MiraiGraphicalUIController : Controller(), MiraiConsoleUI {
     }
 
     override fun prePushBot(identity: Long) = Platform.runLater {
-        BotModel(identity).also {
-            cache[identity] = it
-            botList.add(it)
+        if (!cache.containsKey(identity)) {
+            BotModel(identity).also {
+                cache[identity] = it
+                botList.add(it)
+            }
         }
     }
 

From 62e71ef3a5d8165178cb028fae248518aa4b2b6d Mon Sep 17 00:00:00 2001
From: ryoii <ryoii@foxmail.com>
Date: Mon, 30 Mar 2020 20:17:23 +0800
Subject: [PATCH 3/6] Graphical logout bot

---
 .../controller/MiraiGraphicalUIController.kt  | 10 +++++++
 .../graphical/stylesheet/PrimaryStyleSheet.kt | 16 +++++++++--
 .../mamoe/mirai/console/graphical/util/SVG.kt | 15 ++++++++++
 .../console/graphical/view/PrimaryView.kt     | 28 +++++++++++++++++--
 4 files changed, 64 insertions(+), 5 deletions(-)
 create mode 100644 mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/util/SVG.kt

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 793db0a96..dba5bc9e7 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
@@ -5,6 +5,7 @@ import javafx.collections.ObservableList
 import javafx.stage.Modality
 import javafx.stage.StageStyle
 import kotlinx.coroutines.delay
+import kotlinx.coroutines.isActive
 import net.mamoe.mirai.Bot
 import net.mamoe.mirai.console.command.CommandManager
 import net.mamoe.mirai.console.command.CommandManager.runCommand
@@ -42,6 +43,15 @@ class MiraiGraphicalUIController : Controller(), MiraiConsoleUI {
         CommandManager.runCommand(ConsoleCommandSender, "/login $qq $psd")
     }
 
+    fun logout(qq: Long) {
+        cache.remove(qq)?.apply {
+            botList.remove(this)
+            if (botProperty.value != null && bot.isActive) {
+                bot.close()
+            }
+        }
+    }
+
     fun sendCommand(command: String) = runCommand(ConsoleCommandSender, command)
 
     override fun pushLog(identity: Long, message: String) = Platform.runLater {
diff --git a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/stylesheet/PrimaryStyleSheet.kt b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/stylesheet/PrimaryStyleSheet.kt
index 58ded3be4..adbec3b80 100644
--- a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/stylesheet/PrimaryStyleSheet.kt
+++ b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/stylesheet/PrimaryStyleSheet.kt
@@ -69,9 +69,21 @@ class PrimaryStyleSheet : BaseStyleSheet() {
                         backgroundColor += c(100, 100, 100, 0.4)
                         backgroundRadius += box(5.px)
 
-                        textFill = c(fontColor)
-                        fontWeight = FontWeight.BOLD
+                        label {
+                            textFill = c(fontColor)
+                            fontWeight = FontWeight.BOLD
+                        }
 
+                        button {
+                            opacity = 0.0
+                            backgroundRadius += box(10.px)
+                            backgroundColor += c(fontColor, 0.1)
+                            cursor = Cursor.HAND
+
+                            and(hover) {
+                                opacity = 1.0
+                            }
+                        }
                     }
                 }
             }
diff --git a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/util/SVG.kt b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/util/SVG.kt
new file mode 100644
index 000000000..442a18188
--- /dev/null
+++ b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/util/SVG.kt
@@ -0,0 +1,15 @@
+package net.mamoe.mirai.console.graphical.util
+
+import com.jfoenix.svg.SVGGlyph
+import javafx.scene.paint.Color
+
+class SVG {
+    companion object {
+        var close = SVGGlyph(
+            0,
+            "CLOSE",
+            "M810 274l-238 238 238 238-60 60-238-238-238 238-60-60 238-238-238-238 60-60 238 238 238-238z",
+            Color.WHITE
+        ).apply { setSize(8.0, 8.0) }
+    }
+}
\ 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 ebaaefe04..8399373c5 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
@@ -5,18 +5,21 @@ import com.jfoenix.controls.JFXListCell
 import javafx.collections.ObservableList
 import javafx.geometry.Insets
 import javafx.geometry.Pos
+import javafx.scene.control.Alert
+import javafx.scene.control.ButtonType
 import javafx.scene.control.Tab
 import javafx.scene.control.TabPane
 import javafx.scene.image.Image
 import javafx.scene.input.KeyCode
+import javafx.scene.layout.Priority
 import javafx.stage.FileChooser
 import kotlinx.coroutines.runBlocking
 import net.mamoe.mirai.console.graphical.controller.MiraiGraphicalUIController
 import net.mamoe.mirai.console.graphical.model.BotModel
+import net.mamoe.mirai.console.graphical.util.*
 import net.mamoe.mirai.console.graphical.util.jfxButton
 import net.mamoe.mirai.console.graphical.util.jfxListView
 import net.mamoe.mirai.console.graphical.util.jfxTabPane
-import net.mamoe.mirai.console.graphical.util.myButtonBar
 import tornadofx.*
 
 class PrimaryView : View() {
@@ -72,8 +75,27 @@ class PrimaryView : View() {
                         override fun updateItem(item: BotModel?, empty: Boolean) {
                             super.updateItem(item, empty)
                             if (item != null && !empty) {
-                                graphic = null
-                                text = item.uin.toString()
+                                graphic = hbox {
+
+                                    alignment = Pos.CENTER_LEFT
+
+                                    label(item.uin.toString())
+                                    pane {
+                                        hgrow = Priority.ALWAYS
+                                    }
+                                    jfxButton(graphic = SVG.close) {
+                                        buttonType = JFXButton.ButtonType.FLAT
+                                        tooltip("退出登录")
+                                    }.action {
+                                        alert(Alert.AlertType.CONFIRMATION, "${item.uin}将会退出登录,是否确认") {
+                                            if (it == ButtonType.OK) {
+                                                tab?.close()
+                                                controller.logout(item.uin)
+                                            }
+                                        }
+                                    }
+                                }
+                                text = ""
                             } else {
                                 graphic = null
                                 text = ""

From 25083f8b2e2b750933ae54c892b8e1bc4858a05d Mon Sep 17 00:00:00 2001
From: ryoii <ryoii@foxmail.com>
Date: Mon, 30 Mar 2020 20:40:38 +0800
Subject: [PATCH 4/6] Graphical log color

---
 .../graphical/controller/MiraiGraphicalUIController.kt   | 4 ++--
 .../net/mamoe/mirai/console/graphical/model/BotModel.kt  | 2 +-
 .../console/graphical/stylesheet/PrimaryStyleSheet.kt    | 9 +++++++++
 .../mamoe/mirai/console/graphical/view/PrimaryView.kt    | 9 ++++++---
 4 files changed, 18 insertions(+), 6 deletions(-)

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 dba5bc9e7..80c8f0dfd 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
@@ -27,7 +27,7 @@ class MiraiGraphicalUIController : Controller(), MiraiConsoleUI {
     private val settingModel = find<GlobalSettingModel>()
     private val loginSolver = GraphicalLoginSolver()
     private val cache = mutableMapOf<Long, BotModel>()
-    val mainLog = observableListOf<String>()
+    val mainLog = observableListOf<Pair<String, String>>()
 
 
     val botList = observableListOf<BotModel>()
@@ -69,7 +69,7 @@ class MiraiGraphicalUIController : Controller(), MiraiConsoleUI {
             } else {
                 cache[identity]?.logHistory
             }?.apply {
-                add("[$time] $identityStr $message")
+                add("[$time] $identityStr $message" to priority.name)
                 trim()
             }
         }
diff --git a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/model/BotModel.kt b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/model/BotModel.kt
index 54de54c76..660948f35 100644
--- a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/model/BotModel.kt
+++ b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/model/BotModel.kt
@@ -11,7 +11,7 @@ class BotModel(val uin: Long) {
     val botProperty = SimpleObjectProperty<Bot>(null)
     var bot: Bot by botProperty
 
-    val logHistory = observableListOf<String>()
+    val logHistory = observableListOf<Pair<String, String>>()
     val admins = observableListOf<Long>()
 }
 
diff --git a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/stylesheet/PrimaryStyleSheet.kt b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/stylesheet/PrimaryStyleSheet.kt
index adbec3b80..9bb6628e5 100644
--- a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/stylesheet/PrimaryStyleSheet.kt
+++ b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/stylesheet/PrimaryStyleSheet.kt
@@ -124,6 +124,15 @@ class PrimaryStyleSheet : BaseStyleSheet() {
                 }
 
                 listCell {
+
+                    and(":WARNING") {
+                        backgroundColor += c("FFFF00", 0.3) // Yellow
+                    }
+
+                    and(":ERROR") {
+                        backgroundColor += c("FF0000", 0.3) // Red
+                    }
+
                     and(":selected") {
                         backgroundColor += c(stressColor, 1.0)
                     }
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 8399373c5..a871a17b3 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
@@ -151,7 +151,7 @@ private fun TabPane.fixedTab(title: String) = tab(title) { isClosable = false }
 
 private fun TabPane.logTab(
     text: String? = null,
-    logs: ObservableList<String>,
+    logs: ObservableList<Pair<String, String>>,
     closeable: Boolean = true,
     op: Tab.() -> Unit = {}
 ) = tab(text) {
@@ -174,7 +174,7 @@ private fun TabPane.logTab(
                     path.firstOrNull()?.run {
                         if (!exists()) createNewFile()
                         writer().use {
-                            logs.forEach { log -> it.appendln(log) }
+                            logs.forEach { log -> it.appendln(log.first) }
                         }
                         true
                     } ?: false
@@ -188,7 +188,10 @@ private fun TabPane.logTab(
 
             fitToParentSize()
             cellFormat {
-                graphic = label(it) {
+
+                addPseudoClass(it.second)
+
+                graphic = label(it.first) {
                     maxWidthProperty().bind(this@listview.widthProperty())
                     isWrapText = true
                 }

From e7f1c590966ea179f8e4d6e1df1416be91eddea8 Mon Sep 17 00:00:00 2001
From: Him188 <Him188@mamoe.net>
Date: Mon, 30 Mar 2020 20:54:00 +0800
Subject: [PATCH 5/6] Fix againstPermission

---
 .../net/mamoe/mirai/console/plugins/PluginManager.kt | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/PluginManager.kt b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/PluginManager.kt
index 215975016..6a47a4e84 100644
--- a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/PluginManager.kt
+++ b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/PluginManager.kt
@@ -307,9 +307,11 @@ private val trySetAccessibleMethod: Method? = runCatching {
 }.getOrNull()
 
 private fun Constructor<out PluginBase>.againstPermission() {
-    trySetAccessibleMethod?.let { it.invoke(this, true) }
-        ?: kotlin.runCatching {
-            @Suppress("DEPRECATED")
-            this.isAccessible = true
-        }
+    kotlin.runCatching {
+        trySetAccessibleMethod?.let { it.invoke(this) }
+            ?: kotlin.runCatching {
+                @Suppress("DEPRECATED")
+                this.isAccessible = true
+            }
+    }
 }
\ No newline at end of file

From 85ec80314c5f0cdeb1708306e3b83158084608d0 Mon Sep 17 00:00:00 2001
From: ryoii <ryoii@foxmail.com>
Date: Mon, 30 Mar 2020 21:32:40 +0800
Subject: [PATCH 6/6] Graphical add contextMenu for log list items

---
 .../mirai/console/graphical/view/PrimaryView.kt      | 12 ++++++++++++
 1 file changed, 12 insertions(+)

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 a871a17b3..a50453e12 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
@@ -10,6 +10,7 @@ import javafx.scene.control.ButtonType
 import javafx.scene.control.Tab
 import javafx.scene.control.TabPane
 import javafx.scene.image.Image
+import javafx.scene.input.Clipboard
 import javafx.scene.input.KeyCode
 import javafx.scene.layout.Priority
 import javafx.stage.FileChooser
@@ -21,6 +22,7 @@ import net.mamoe.mirai.console.graphical.util.jfxButton
 import net.mamoe.mirai.console.graphical.util.jfxListView
 import net.mamoe.mirai.console.graphical.util.jfxTabPane
 import tornadofx.*
+import tornadofx.Stylesheet.Companion.contextMenu
 
 class PrimaryView : View() {
 
@@ -194,6 +196,16 @@ private fun TabPane.logTab(
                 graphic = label(it.first) {
                     maxWidthProperty().bind(this@listview.widthProperty())
                     isWrapText = true
+
+
+                    contextmenu {
+                        item("复制").action {
+                            Clipboard.getSystemClipboard().putString(it.first)
+                        }
+                        item("删除").action {
+                            logs.remove(it)
+                        }
+                    }
                 }
             }
         }