Browse Source

Merge remote-tracking branch 'origin/master'

jiahua.liu 6 years ago
parent
commit
3844ef3311

+ 7 - 13
.github/workflows/main.yml

@@ -8,16 +8,10 @@ jobs:
     runs-on: ubuntu-latest
 
     steps:
-    - uses: actions/checkout@v1
-    - name: Setup Java JDK
-      uses: actions/[email protected]
-      with:
-        # The Java version to make available on the path. Takes a whole or semver Java version, or 1.x syntax (e.g. 1.8 => Java 8.x)
-        java-version: 11
-        # The package type (jre, jdk, jdk+fx)
-        java-package: jdk+fx
-    - name: Gradle Command
-      uses: eskatos/gradle-command-action@v1
-      with:
-        # Gradle command line arguments, see gradle --help
-        arguments: build -x mirai-core:jvmTest
+      - uses: actions/checkout@v1
+      - name: setup-android
+        uses: msfjarvis/[email protected]
+        with:
+          # Gradle tasks to run - If you want to run ./gradlew assemble, specify assemble here.
+          gradleTasks: build -x mirai-core:jvmTest
+

+ 7 - 0
mirai-console-graphical/build.gradle.kts

@@ -1,9 +1,15 @@
 plugins {
     id("kotlinx-serialization")
+    id("org.openjfx.javafxplugin") version "0.0.8"
     id("kotlin")
     id("java")
 }
 
+javafx {
+    version = "11"
+    modules = listOf("javafx.controls")
+    //mainClassName = "Application"
+}
 
 apply(plugin = "com.github.johnrengelman.shadow")
 
@@ -29,6 +35,7 @@ dependencies {
     api(project(":mirai-console"))
     runtimeOnly(files("../mirai-core-qqandroid/build/classes/kotlin/jvm/main"))
     api(group = "no.tornado", name = "tornadofx", version = "1.7.19")
+    api(group = "com.jfoenix", name = "jfoenix", version = "9.0.8")
     api("org.bouncycastle:bcprov-jdk15on:1.64")
     // classpath is not set correctly by IDE
 }

+ 44 - 0
mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/util/JFoenixAdaptor.kt

@@ -0,0 +1,44 @@
+package net.mamoe.mirai.console.graphical.util
+
+import com.jfoenix.controls.*
+import javafx.beans.value.ObservableValue
+import javafx.collections.ObservableList
+import javafx.event.EventTarget
+import javafx.scene.Node
+import javafx.scene.control.*
+import tornadofx.SortedFilteredList
+import tornadofx.attachTo
+import tornadofx.bind
+
+internal fun EventTarget.jfxTabPane(op: TabPane.() -> Unit = {}) = JFXTabPane().attachTo(this, op)
+
+internal fun EventTarget.jfxButton(text: String = "", graphic: Node? = null, op: Button.() -> Unit = {}) =
+    JFXButton(text).attachTo(this, op) {
+        if (graphic != null) it.graphic = graphic
+    }
+
+fun EventTarget.jfxTextfield(value: String? = null, op: TextField.() -> Unit = {}) = JFXTextField().attachTo(this, op) {
+    if (value != null) it.text = value
+}
+
+fun EventTarget.jfxTextfield(property: ObservableValue<String>, op: TextField.() -> Unit = {}) = jfxTextfield().apply {
+    bind(property)
+    op(this)
+}
+
+fun EventTarget.jfxPasswordfield(value: String? = null, op: TextField.() -> Unit = {}) = JFXPasswordField().attachTo(this, op) {
+    if (value != null) it.text = value
+}
+
+fun EventTarget.jfxPasswordfield(property: ObservableValue<String>, op: TextField.() -> Unit = {}) = jfxPasswordfield().apply {
+    bind(property)
+    op(this)
+}
+
+internal fun <T> EventTarget.jfxListView(values: ObservableList<T>? = null, op: ListView<T>.() -> Unit = {}) =
+    JFXListView<T>().attachTo(this, op) {
+        if (values != null) {
+            if (values is SortedFilteredList<T>) values.bindTo(it)
+            else it.items = values
+        }
+    }

+ 12 - 8
mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/view/LoginFragment.kt

@@ -1,27 +1,31 @@
 package net.mamoe.mirai.console.graphical.view
 
+import com.jfoenix.controls.JFXTextField
 import javafx.beans.property.SimpleStringProperty
 import net.mamoe.mirai.console.graphical.controller.MiraiGraphicalUIController
+import net.mamoe.mirai.console.graphical.util.jfxButton
+import net.mamoe.mirai.console.graphical.util.jfxPasswordfield
+import net.mamoe.mirai.console.graphical.util.jfxTextfield
 import tornadofx.*
 
 class LoginFragment : Fragment() {
 
     private val controller = find<MiraiGraphicalUIController>(FX.defaultScope)
-    private val qq = SimpleStringProperty()
-    private val psd = SimpleStringProperty()
+    private val qq = SimpleStringProperty("0")
+    private val psd = SimpleStringProperty("")
 
     override val root = form {
         fieldset("登录") {
             field("QQ") {
-                textfield(qq)
+                jfxTextfield(qq)
             }
             field("密码") {
-                passwordfield(psd)
-            }
-            button("登录").action {
-                controller.login(qq.value, psd.value)
-                close()
+                jfxPasswordfield(psd)
             }
         }
+        jfxButton("登录").action {
+            controller.login(qq.value, psd.value)
+            close()
+        }
     }
 }

+ 80 - 28
mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/view/PrimaryView.kt

@@ -1,10 +1,20 @@
 package net.mamoe.mirai.console.graphical.view
 
+import com.jfoenix.controls.JFXListCell
+import javafx.geometry.Insets
+import javafx.geometry.Pos
+import javafx.scene.control.Tab
 import javafx.scene.control.TabPane
-import javafx.stage.Modality
-import net.mamoe.mirai.Bot
+import javafx.scene.image.Image
+import javafx.scene.paint.Color
+import javafx.scene.text.FontWeight
 import net.mamoe.mirai.console.graphical.controller.MiraiGraphicalUIController
+import net.mamoe.mirai.console.graphical.model.BotModel
+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 java.io.FileInputStream
 
 class PrimaryView : View() {
 
@@ -12,45 +22,87 @@ class PrimaryView : View() {
 
     override val root = borderpane {
 
-        top = menubar {
-            menu("机器人") {
-                item("登录").action {
-                    find<LoginFragment>().openModal(
-                        modality = Modality.APPLICATION_MODAL,
-                        resizable = false
-                    )
+        prefWidth = 1000.0
+        prefHeight = 650.0
+
+        left = vbox {
+
+            imageview(Image(PrimaryView::class.java.classLoader.getResourceAsStream("logo.png")))
+
+            // bot list
+            jfxListView(controller.botList) {
+                fitToParentSize()
+
+                setCellFactory {
+                    object : JFXListCell<BotModel>() {
+                        var tab: Tab? = null
+
+                        init {
+                            onDoubleClick {
+                                if (tab == null) {
+                                    (center as TabPane).tab(item.uin.toString()) {
+                                        listview(item.logHistory)
+                                        onDoubleClick { close() }
+                                        tab = this
+                                    }
+                                } else {
+                                    (center as TabPane).tabs.add(tab)
+                                }
+                                tab?.select()
+                            }
+                        }
+
+                        override fun updateItem(item: BotModel?, empty: Boolean) {
+                            super.updateItem(item, empty)
+                            if (item != null && !empty) {
+                                graphic = null
+                                text = item.uin.toString()
+                            } else {
+                                graphic = null
+                                text = ""
+                            }
+                        }
+                    }
                 }
             }
-        }
-
-        left = listview(controller.botList) {
-            fitToParentHeight()
 
-            cellFormat {
+            hbox {
+                padding = Insets(10.0)
+                spacing = 10.0
+                alignment = Pos.CENTER
 
-                graphic = vbox {
-                    label(it.uin.toString())
-//                    label(stringBinding(it.botProperty) { if (value != null) value.nick else "登陆中" })
+                jfxButton("L").action {
+                    find<LoginFragment>().openModal()
                 }
+                jfxButton("P")
+                jfxButton("S")
 
-                onDoubleClick {
-                    (center as TabPane).tab(it.uin.toString()) {
-                        listview(it.logHistory)
 
-                        isClosable = true
-                        select()
-                    }
+                style { backgroundColor += c("00BCD4") }
+                children.style(true) {
+                    backgroundColor += c("00BCD4")
+                    fontSize = 15.px
+                    fontWeight = FontWeight.BOLD
+                    textFill = Color.WHITE
+                    borderRadius += box(25.px)
+                    backgroundRadius += box(25.px)
                 }
             }
         }
 
-        center = tabpane {
+        center = jfxTabPane {
             tab("Main") {
-                listview(controller.mainLog)
+                listview(controller.mainLog) {
 
-                isClosable = false
+                    fitToParentSize()
+                    cellFormat {
+                        graphic = label(it) {
+                            maxWidthProperty().bind([email protected]())
+                            isWrapText = true
+                        }
+                    }
+                }
             }
         }
     }
-
-}
+}

BIN
mirai-console-graphical/src/main/resources/logo.png


+ 20 - 2
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/MessageSubscribers.kt

@@ -28,6 +28,8 @@ import kotlin.contracts.contract
 
 /**
  * 订阅来自所有 [Bot] 的所有联系人的消息事件. 联系人可以是任意群或任意好友或临时会话.
+ *
+ * @see CoroutineScope.incoming
  */
 @UseExperimental(ExperimentalContracts::class)
 @MessageDsl
@@ -49,6 +51,8 @@ inline fun <R> CoroutineScope.subscribeMessages(crossinline listeners: MessageSu
 
 /**
  * 订阅来自所有 [Bot] 的所有群消息事件
+ *
+ * @see CoroutineScope.incoming
  */
 @UseExperimental(ExperimentalContracts::class)
 @MessageDsl
@@ -65,6 +69,8 @@ inline fun <R> CoroutineScope.subscribeGroupMessages(crossinline listeners: Mess
 
 /**
  * 订阅来自所有 [Bot] 的所有好友消息事件
+ *
+ * @see CoroutineScope.incoming
  */
 @UseExperimental(ExperimentalContracts::class)
 @MessageDsl
@@ -81,6 +87,8 @@ inline fun <R> CoroutineScope.subscribeFriendMessages(crossinline listeners: Mes
 
 /**
  * 订阅来自这个 [Bot] 的所有联系人的消息事件. 联系人可以是任意群或任意好友或临时会话.
+ *
+ * @see CoroutineScope.incoming
  */
 @UseExperimental(ExperimentalContracts::class)
 @MessageDsl
@@ -97,6 +105,8 @@ inline fun <R> Bot.subscribeMessages(crossinline listeners: MessageSubscribersBu
 
 /**
  * 订阅来自这个 [Bot] 的所有群消息事件
+ *
+ * @see CoroutineScope.incoming
  */
 @UseExperimental(ExperimentalContracts::class)
 @MessageDsl
@@ -113,6 +123,8 @@ inline fun <R> Bot.subscribeGroupMessages(crossinline listeners: MessageSubscrib
 
 /**
  * 订阅来自这个 [Bot] 的所有好友消息事件.
+ *
+ * @see CoroutineScope.incoming
  */
 @UseExperimental(ExperimentalContracts::class)
 @MessageDsl
@@ -129,9 +141,15 @@ inline fun <R> Bot.subscribeFriendMessages(crossinline listeners: MessageSubscri
 
 /**
  * 返回一个指定事件的接收通道
+ *
+ * @param capacity 同 [Channel] 的参数, 参见 [Channel.Factory] 中的常量.
+ *
+ * @see subscribeFriendMessages
+ * @see subscribeMessages
+ * @see subscribeGroupMessages
  */
-inline fun <reified E : Event> Bot.incoming(): ReceiveChannel<E> {
-    return Channel<E>(8).apply {
+inline fun <reified E : Event> CoroutineScope.incoming(capacity: Int = Channel.RENDEZVOUS): ReceiveChannel<E> {
+    return Channel<E>(capacity).apply {
         subscribeAlways<E> {
             send(this)
         }

+ 11 - 2
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/internal/InternalEventListeners.kt

@@ -90,6 +90,15 @@ internal object EventListenerManager {
 
     private val lock = atomic(false)
 
+    private fun setLockValue(value: Boolean) {
+        lock.value = value
+    }
+
+    @Suppress("BooleanLiteralArgument")
+    private fun trySetLockTrue(): Boolean {
+        return lock.compareAndSet(false, true)
+    }
+
     @Suppress("UNCHECKED_CAST", "BooleanLiteralArgument")
     internal tailrec fun <E : Event> get(clazz: KClass<out E>): EventListeners<E> {
         registries.forEach {
@@ -97,10 +106,10 @@ internal object EventListenerManager {
                 return it.listeners as EventListeners<E>
             }
         }
-        if (lock.compareAndSet(false, true)) {
+        if (trySetLockTrue()) {
             val registry = Registry(clazz, EventListeners())
             registries.addLast(registry)
-            lock.value = false
+            setLockValue(false)
             return registry.listeners as EventListeners<E>
         }
         return get(clazz)

+ 3 - 1
mirai-demos/mirai-demo-1/src/main/java/demo/subscribe/SubscribeSamples.kt

@@ -28,8 +28,10 @@ import net.mamoe.mirai.message.sendAsImageTo
 import net.mamoe.mirai.qqandroid.Bot
 import net.mamoe.mirai.qqandroid.QQAndroid
 import net.mamoe.mirai.utils.FileBasedDeviceInfo
+import net.mamoe.mirai.utils.MiraiInternalAPI
 import java.io.File
 
+@MiraiInternalAPI
 private fun readTestAccount(): BotAccount? {
     val file = File("testAccount.txt")
     if (!file.exists() || !file.canRead()) {
@@ -59,7 +61,7 @@ suspend fun main() {
     bot.messageDSL()
     directlySubscribe(bot)
 
-    bot.network.awaitDisconnection()//等到直到断开连接
+    bot.join()//等到直到断开连接
 }
 
 /**

+ 1 - 1
mirai-demos/mirai-demo-gentleman/src/main/kotlin/demo/gentleman/Main.kt

@@ -176,7 +176,7 @@ suspend fun main() {
 
     }
 
-    bot.network.awaitDisconnection()//等到直到断开连接
+    bot.join()//等到直到断开连接
 }
 
 private fun newTestTempFile(filename: String = "${UUID.randomUUID()}", suffix: String = ".tmp"): File =

+ 16 - 18
settings.gradle

@@ -44,7 +44,6 @@ include(':mirai-core-qqandroid')
 
 include(':mirai-japt')
 include(':mirai-console')
-include(':mirai-console-graphical')
 include(':mirai-console-terminal')
 //include(':mirai-api')
 include(':mirai-api-http')
@@ -54,24 +53,23 @@ include(':mirai-demos:mirai-demo-java')
 include(':mirai-plugins')
 include(':mirai-plugins:image-sender')
 
-def javaVersion = System.getProperty("java.version")
-def versionPos = javaVersion.indexOf(".")
-if (versionPos==-1) versionPos = javaVersion.indexOf("-")
-if (versionPos==-1){
-    println("jdk version unknown")
-}else{
-    def javaVersionNum = javaVersion.substring(0, versionPos).toInteger()
-    if (javaVersionNum >= 11) {
-        println("jdk版本为 "+ javaVersionNum)
-        //include(':mirai-debug')
-    } else {
-        println("当前使用的 JDK 版本为 ${System.getProperty("java.version")}, 最低需要 JDK 11 才能引入模块 `:mirai-debug`")
+try{
+    def javaVersion = System.getProperty("java.version")
+    def versionPos = javaVersion.indexOf(".")
+    if (versionPos==-1) versionPos = javaVersion.indexOf("-")
+    if (versionPos==-1){
+        println("jdk version unknown")
+    }else{
+        def javaVersionNum = javaVersion.substring(0, versionPos).toInteger()
+        if (javaVersionNum >= 11) {
+            println("jdk版本为 "+ javaVersionNum)
+            include(':mirai-console-graphical')
+        } else {
+            println("当前使用的 JDK 版本为 ${System.getProperty("java.version")}, 最低需要 JDK 11 才能引入模块 `:mirai-debug`")
+        }
     }
-}
+}catch(Exception ignored){
 
-project(':mirai-demos:mirai-demo-1').projectDir = file('mirai-demos/mirai-demo-1')
-project(':mirai-demos:mirai-demo-gentleman').projectDir = file('mirai-demos/mirai-demo-gentleman')
-project(':mirai-demos:mirai-demo-java').projectDir = file('mirai-demos/mirai-demo-java')
-project(':mirai-plugins:image-sender').projectDir = file('mirai-plugins/image-sender')
+}
 
 enableFeaturePreview('GRADLE_METADATA')