mirror of
https://github.com/mamoe/mirai.git
synced 2025-02-03 04:32:25 +08:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
3844ef3311
20
.github/workflows/main.yml
vendored
20
.github/workflows/main.yml
vendored
@ -8,16 +8,10 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Setup Java JDK
|
||||
uses: actions/setup-java@v1.3.0
|
||||
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/setup-android@0.2
|
||||
with:
|
||||
# Gradle tasks to run - If you want to run ./gradlew assemble, specify assemble here.
|
||||
gradleTasks: build -x mirai-core:jvmTest
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
@ -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 = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hbox {
|
||||
padding = Insets(10.0)
|
||||
spacing = 10.0
|
||||
alignment = Pos.CENTER
|
||||
|
||||
jfxButton("L").action {
|
||||
find<LoginFragment>().openModal()
|
||||
}
|
||||
jfxButton("P")
|
||||
jfxButton("S")
|
||||
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
left = listview(controller.botList) {
|
||||
fitToParentHeight()
|
||||
center = jfxTabPane {
|
||||
tab("Main") {
|
||||
listview(controller.mainLog) {
|
||||
|
||||
cellFormat {
|
||||
|
||||
graphic = vbox {
|
||||
label(it.uin.toString())
|
||||
// label(stringBinding(it.botProperty) { if (value != null) value.nick else "登陆中" })
|
||||
}
|
||||
|
||||
onDoubleClick {
|
||||
(center as TabPane).tab(it.uin.toString()) {
|
||||
listview(it.logHistory)
|
||||
|
||||
isClosable = true
|
||||
select()
|
||||
fitToParentSize()
|
||||
cellFormat {
|
||||
graphic = label(it) {
|
||||
maxWidthProperty().bind(this@listview.widthProperty())
|
||||
isWrapText = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
center = tabpane {
|
||||
tab("Main") {
|
||||
listview(controller.mainLog)
|
||||
|
||||
isClosable = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
BIN
mirai-console-graphical/src/main/resources/logo.png
Normal file
BIN
mirai-console-graphical/src/main/resources/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.9 KiB |
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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()//等到直到断开连接
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -176,7 +176,7 @@ suspend fun main() {
|
||||
|
||||
}
|
||||
|
||||
bot.network.awaitDisconnection()//等到直到断开连接
|
||||
bot.join()//等到直到断开连接
|
||||
}
|
||||
|
||||
private fun newTestTempFile(filename: String = "${UUID.randomUUID()}", suffix: String = ".tmp"): File =
|
||||
|
@ -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')
|
Loading…
Reference in New Issue
Block a user