mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-24 06:50:08 +08:00
Remove mirai-console-graphical
This commit is contained in:
parent
00d7430f06
commit
53149d1d36
@ -1,6 +0,0 @@
|
|||||||
### Mirai Console Graphical
|
|
||||||
支持windows/mac
|
|
||||||
有正式UI界面实现的CONSOLE
|
|
||||||
优点: 适合新手/完全不懂编程的/界面美丽
|
|
||||||
缺点: 不能在linux服务器运行
|
|
||||||
所使用插件系统与terminal版本一致 可以来回切换
|
|
@ -1,73 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2019-2021 Mamoe Technologies and contributors.
|
|
||||||
*
|
|
||||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
|
||||||
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
|
||||||
*
|
|
||||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
|
||||||
*/
|
|
||||||
|
|
||||||
plugins {
|
|
||||||
id("kotlinx-serialization")
|
|
||||||
id("org.openjfx.javafxplugin") version "0.0.8"
|
|
||||||
id("kotlin")
|
|
||||||
id("java")
|
|
||||||
`maven-publish`
|
|
||||||
}
|
|
||||||
|
|
||||||
javafx {
|
|
||||||
version = "13.0.2"
|
|
||||||
modules = listOf("javafx.controls")
|
|
||||||
//mainClassName = "Application"
|
|
||||||
}
|
|
||||||
|
|
||||||
apply(plugin = "com.github.johnrengelman.shadow")
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
tasks.withType<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar>() {
|
|
||||||
manifest {
|
|
||||||
attributes["Main-Class"] = "net.mamoe.mirai.console.graphical.MiraiGraphicalLoader"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
version = Versions.Mirai.consoleGraphical
|
|
||||||
|
|
||||||
description = "Graphical frontend for mirai-console"
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
compileOnly("net.mamoe:mirai-core:${Versions.core}")
|
|
||||||
implementation(project(":mirai-console"))
|
|
||||||
|
|
||||||
api(group = "no.tornado", name = "tornadofx", version = "1.7.19")
|
|
||||||
api(group = "com.jfoenix", name = "jfoenix", version = "9.0.8")
|
|
||||||
|
|
||||||
testApi(project(":mirai-console"))
|
|
||||||
testApi(kotlinx("coroutines-core", Versions.coroutines))
|
|
||||||
testApi(group = "org.yaml", name = "snakeyaml", version = "1.25")
|
|
||||||
testApi("net.mamoe:mirai-core:${Versions.core}")
|
|
||||||
testApi("net.mamoe:mirai-core-qqandroid:${Versions.core}")
|
|
||||||
}
|
|
||||||
|
|
||||||
kotlin {
|
|
||||||
sourceSets {
|
|
||||||
all {
|
|
||||||
|
|
||||||
languageSettings.useExperimentalAnnotation("kotlin.Experimental")
|
|
||||||
languageSettings.useExperimentalAnnotation("kotlin.RequiresOptIn")
|
|
||||||
languageSettings.progressiveMode = true
|
|
||||||
languageSettings.useExperimentalAnnotation("net.mamoe.mirai.utils.MiraiInternalAPI")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
|
|
||||||
kotlinOptions.jvmTarget = "1.8"
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("DEPRECATION")
|
|
||||||
val sourcesJar by tasks.registering(Jar::class) {
|
|
||||||
classifier = "sources"
|
|
||||||
from(sourceSets.main.get().allSource)
|
|
||||||
}
|
|
@ -1,35 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
|
||||||
*
|
|
||||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
|
||||||
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link.
|
|
||||||
*
|
|
||||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.mamoe.mirai.console.graphical
|
|
||||||
|
|
||||||
import kotlinx.coroutines.cancel
|
|
||||||
import net.mamoe.mirai.console.MiraiConsole
|
|
||||||
import tornadofx.launch
|
|
||||||
import kotlin.concurrent.thread
|
|
||||||
|
|
||||||
class MiraiConsoleGraphicalLoader {
|
|
||||||
companion object {
|
|
||||||
internal var coreVersion :String = "0.0.0"
|
|
||||||
internal var consoleVersion: String = "0.0.0"
|
|
||||||
@JvmStatic
|
|
||||||
fun load(
|
|
||||||
coreVersion: String,
|
|
||||||
consoleVersion: String
|
|
||||||
) {
|
|
||||||
this.coreVersion = coreVersion
|
|
||||||
this.consoleVersion = consoleVersion
|
|
||||||
Runtime.getRuntime().addShutdownHook(thread(start = false) {
|
|
||||||
MiraiConsole.cancel()
|
|
||||||
})
|
|
||||||
launch<MiraiGraphicalUI>()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,43 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
|
||||||
*
|
|
||||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
|
||||||
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link.
|
|
||||||
*
|
|
||||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.mamoe.mirai.console.graphical
|
|
||||||
|
|
||||||
import net.mamoe.mirai.console.MiraiConsole
|
|
||||||
import net.mamoe.mirai.console.graphical.controller.MiraiGraphicalFrontEndController
|
|
||||||
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
|
|
||||||
// fun main(args: Array<String>) {
|
|
||||||
// launch<MiraiGraphicalUI>(args)
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
class MiraiGraphicalUI : App(Decorator::class, PrimaryStyleSheet::class) {
|
|
||||||
|
|
||||||
override fun init() {
|
|
||||||
super.init()
|
|
||||||
MiraiConsole.start(
|
|
||||||
find<MiraiGraphicalFrontEndController>(),
|
|
||||||
MiraiConsoleGraphicalLoader.coreVersion,
|
|
||||||
MiraiConsoleGraphicalLoader.consoleVersion
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun stop() {
|
|
||||||
super.stop()
|
|
||||||
MiraiConsole.stop()
|
|
||||||
exitProcess(0)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,214 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
|
||||||
*
|
|
||||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
|
||||||
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link.
|
|
||||||
*
|
|
||||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.mamoe.mirai.console.graphical.controller
|
|
||||||
|
|
||||||
import javafx.application.Platform
|
|
||||||
import javafx.collections.ObservableList
|
|
||||||
import javafx.stage.Modality
|
|
||||||
import javafx.stage.StageStyle
|
|
||||||
import kotlinx.coroutines.delay
|
|
||||||
import kotlinx.coroutines.isActive
|
|
||||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
|
||||||
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.event.ReloadEvent
|
|
||||||
import net.mamoe.mirai.console.graphical.model.*
|
|
||||||
import net.mamoe.mirai.console.graphical.view.dialog.InputDialog
|
|
||||||
import net.mamoe.mirai.console.graphical.view.dialog.VerificationCodeFragment
|
|
||||||
import net.mamoe.mirai.console.plugins.PluginManager
|
|
||||||
import net.mamoe.mirai.console.utils.MiraiConsoleFrontEnd
|
|
||||||
import net.mamoe.mirai.network.CustomLoginFailedException
|
|
||||||
import net.mamoe.mirai.utils.LoginSolver
|
|
||||||
import net.mamoe.mirai.utils.MiraiLogger
|
|
||||||
import net.mamoe.mirai.utils.SimpleLogger
|
|
||||||
import net.mamoe.mirai.utils.SimpleLogger.LogPriority
|
|
||||||
import tornadofx.Controller
|
|
||||||
import tornadofx.Scope
|
|
||||||
import tornadofx.find
|
|
||||||
import tornadofx.observableListOf
|
|
||||||
import java.text.SimpleDateFormat
|
|
||||||
import java.util.*
|
|
||||||
import kotlin.collections.List
|
|
||||||
import kotlin.collections.forEach
|
|
||||||
import kotlin.collections.mutableMapOf
|
|
||||||
import kotlin.collections.set
|
|
||||||
import kotlin.coroutines.resume
|
|
||||||
|
|
||||||
class MiraiGraphicalFrontEndController : Controller(), MiraiConsoleFrontEnd {
|
|
||||||
|
|
||||||
private val settingModel = find<GlobalSettingModel>()
|
|
||||||
private val loginSolver = GraphicalLoginSolver()
|
|
||||||
private val cache = mutableMapOf<Long, BotModel>()
|
|
||||||
val mainLog = observableListOf<Pair<String, String>>()
|
|
||||||
|
|
||||||
|
|
||||||
val botList = observableListOf<BotModel>()
|
|
||||||
val pluginList: ObservableList<PluginModel> by lazy(::getPluginsFromConsole)
|
|
||||||
|
|
||||||
private val consoleInfo = ConsoleInfo()
|
|
||||||
|
|
||||||
internal val sdf by lazy { SimpleDateFormat("HH:mm:ss") }
|
|
||||||
|
|
||||||
init {
|
|
||||||
// 监听插件重载事件,以重新从console获取插件列表
|
|
||||||
subscribe<ReloadEvent> {
|
|
||||||
pluginList.clear()
|
|
||||||
|
|
||||||
// 不能直接赋值,pluginList已经被bind,不能更换对象
|
|
||||||
pluginList.addAll(getPluginsFromConsole())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun login(qq: String, psd: String) {
|
|
||||||
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)
|
|
||||||
|
|
||||||
|
|
||||||
private val mainLogger = SimpleLogger(null) { priority: LogPriority, message: String?, e: Throwable? ->
|
|
||||||
Platform.runLater {
|
|
||||||
val time = sdf.format(Date())
|
|
||||||
mainLog.apply {
|
|
||||||
add("[$time] $message" to priority.name)
|
|
||||||
trim()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun loggerFor(identity: Long): MiraiLogger {
|
|
||||||
return if (identity == 0L) return mainLogger
|
|
||||||
else cache[identity]?.logger ?: kotlin.error("bot not found: $identity")
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
override fun prePushBot(identity: Long) = Platform.runLater {
|
|
||||||
if (!cache.containsKey(identity)) {
|
|
||||||
BotModel(identity).also {
|
|
||||||
cache[identity] = it
|
|
||||||
botList.add(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun pushBot(bot: Bot) = Platform.runLater {
|
|
||||||
cache[bot.id]?.bot = bot
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun pushVersion(consoleVersion: String, consoleBuild: String, coreVersion: String) {
|
|
||||||
Platform.runLater {
|
|
||||||
consoleInfo.consoleVersion = consoleVersion
|
|
||||||
consoleInfo.consoleBuild = consoleBuild
|
|
||||||
consoleInfo.coreVersion = coreVersion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun requestInput(hint: String): String =
|
|
||||||
suspendCancellableCoroutine {
|
|
||||||
Platform.runLater {
|
|
||||||
it.resume(InputDialog(hint).open())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun pushBotAdminStatus(identity: Long, admins: List<Long>) = Platform.runLater {
|
|
||||||
cache[identity]?.admins?.setAll(admins)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun createLoginSolver(): LoginSolver = loginSolver
|
|
||||||
|
|
||||||
private fun getPluginsFromConsole(): ObservableList<PluginModel> =
|
|
||||||
PluginManager.getAllPluginDescriptions().map(::PluginModel).toObservable()
|
|
||||||
|
|
||||||
fun checkUpdate(plugin: PluginModel) {
|
|
||||||
pluginList.forEach {
|
|
||||||
if (it.name == plugin.name && it.author == plugin.author) {
|
|
||||||
if (plugin.version > it.version) {
|
|
||||||
it.expired = true
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun ObservableList<*>.trim() {
|
|
||||||
while (size > settingModel.item.maxLongNum) {
|
|
||||||
this.removeAt(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun reloadPlugins() {
|
|
||||||
|
|
||||||
with(PluginManager) {
|
|
||||||
reloadPlugins()
|
|
||||||
}
|
|
||||||
|
|
||||||
fire(ReloadEvent) // 广播插件重载事件
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class GraphicalLoginSolver : LoginSolver() {
|
|
||||||
override suspend fun onSolvePicCaptcha(bot: Bot, data: ByteArray): String? {
|
|
||||||
val code = VerificationCodeModel(VerificationCode(data))
|
|
||||||
|
|
||||||
// UI必须在UI线程执行,requestInput在协程种被调用
|
|
||||||
Platform.runLater {
|
|
||||||
find<VerificationCodeFragment>(Scope(code)).openModal(
|
|
||||||
stageStyle = StageStyle.UNDECORATED,
|
|
||||||
escapeClosesWindow = false,
|
|
||||||
modality = Modality.NONE,
|
|
||||||
resizable = false,
|
|
||||||
block = true
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 阻塞协程直到验证码已经输入
|
|
||||||
while (code.isDirty || code.code.value == null) {
|
|
||||||
delay(1000)
|
|
||||||
if (code.code.value === VerificationCodeFragment.MAGIC_KEY) {
|
|
||||||
throw LoginCancelledManuallyException()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return code.code.value
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
override suspend fun onSolveSliderCaptcha(bot: Bot, url: String): String? {
|
|
||||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun onSolveUnsafeDeviceLoginVerify(bot: Bot, url: String): String? {
|
|
||||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class LoginCancelledManuallyException : CustomLoginFailedException(true, "取消登录")
|
|
@ -1,14 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
|
||||||
*
|
|
||||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
|
||||||
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link.
|
|
||||||
*
|
|
||||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.mamoe.mirai.console.graphical.event
|
|
||||||
|
|
||||||
import tornadofx.FXEvent
|
|
||||||
|
|
||||||
object ReloadEvent : FXEvent()
|
|
@ -1,45 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
|
||||||
*
|
|
||||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
|
||||||
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link.
|
|
||||||
*
|
|
||||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.mamoe.mirai.console.graphical.model
|
|
||||||
|
|
||||||
import javafx.beans.property.SimpleObjectProperty
|
|
||||||
import net.mamoe.mirai.Bot
|
|
||||||
import net.mamoe.mirai.console.graphical.controller.MiraiGraphicalFrontEndController
|
|
||||||
import net.mamoe.mirai.utils.SimpleLogger
|
|
||||||
import tornadofx.*
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
class BotModel(val uin: Long) {
|
|
||||||
val botProperty = SimpleObjectProperty<Bot>(null)
|
|
||||||
var bot: Bot by botProperty
|
|
||||||
|
|
||||||
val logHistory = observableListOf<Pair<String, String>>()
|
|
||||||
val logger: SimpleLogger =
|
|
||||||
SimpleLogger(uin.toString()) { priority: SimpleLogger.LogPriority, message: String?, e: Throwable? ->
|
|
||||||
|
|
||||||
val frontend = find<MiraiGraphicalFrontEndController>()
|
|
||||||
|
|
||||||
frontend.run {
|
|
||||||
logHistory.apply {
|
|
||||||
val time = sdf.format(Date())
|
|
||||||
add("[$time] $uin $message" to priority.name)
|
|
||||||
trim()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val admins = observableListOf<Long>()
|
|
||||||
}
|
|
||||||
|
|
||||||
class BotViewModel(botModel: BotModel? = null) : ItemViewModel<BotModel>(botModel) {
|
|
||||||
val bot = bind(BotModel::botProperty)
|
|
||||||
val logHistory = bind(BotModel::logHistory)
|
|
||||||
val admins = bind(BotModel::admins)
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
|
||||||
*
|
|
||||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
|
||||||
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link.
|
|
||||||
*
|
|
||||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.mamoe.mirai.console.graphical.model
|
|
||||||
|
|
||||||
import javafx.beans.property.SimpleStringProperty
|
|
||||||
import tornadofx.getValue
|
|
||||||
import tornadofx.setValue
|
|
||||||
|
|
||||||
class ConsoleInfo {
|
|
||||||
|
|
||||||
val consoleVersionProperty = SimpleStringProperty()
|
|
||||||
var consoleVersion by consoleVersionProperty
|
|
||||||
|
|
||||||
val consoleBuildProperty = SimpleStringProperty()
|
|
||||||
var consoleBuild by consoleBuildProperty
|
|
||||||
|
|
||||||
val coreVersionProperty = SimpleStringProperty()
|
|
||||||
var coreVersion by coreVersionProperty
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
|
||||||
*
|
|
||||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
|
||||||
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link.
|
|
||||||
*
|
|
||||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.mamoe.mirai.console.graphical.model
|
|
||||||
|
|
||||||
import javafx.beans.property.SimpleLongProperty
|
|
||||||
import tornadofx.ItemViewModel
|
|
||||||
import tornadofx.getValue
|
|
||||||
import tornadofx.setValue
|
|
||||||
|
|
||||||
class GlobalSetting {
|
|
||||||
val maxLogNumProperty = SimpleLongProperty(4096)
|
|
||||||
var maxLongNum: Long by maxLogNumProperty
|
|
||||||
}
|
|
||||||
|
|
||||||
class GlobalSettingModel(setting: GlobalSetting) : ItemViewModel<GlobalSetting>(setting) {
|
|
||||||
constructor() : this(GlobalSetting())
|
|
||||||
|
|
||||||
val maxLogNum = bind(GlobalSetting::maxLogNumProperty)
|
|
||||||
}
|
|
@ -1,39 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
|
||||||
*
|
|
||||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
|
||||||
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link.
|
|
||||||
*
|
|
||||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
|
||||||
*/
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
class PluginModel(
|
|
||||||
val name: String,
|
|
||||||
val version: String,
|
|
||||||
val author: String,
|
|
||||||
val description: String,
|
|
||||||
var insight: PluginCenter.PluginInsight? = null
|
|
||||||
) : RecursiveTreeObject<PluginModel>() {
|
|
||||||
constructor(plugin: PluginDescription) : this(plugin.name, plugin.version, plugin.author, plugin.info)
|
|
||||||
|
|
||||||
val nameProperty = SimpleStringProperty(this, "nameProperty", name)
|
|
||||||
val versionProperty = SimpleStringProperty(this, "versionProperty", version)
|
|
||||||
val authorProperty = SimpleStringProperty(this, "authorProperty", author)
|
|
||||||
val descriptionProperty = SimpleStringProperty(this, "descriptionProperty", description)
|
|
||||||
|
|
||||||
val enabledProperty = SimpleBooleanProperty(this, "enabledProperty")
|
|
||||||
var enabled by enabledProperty
|
|
||||||
|
|
||||||
val expiredProperty = SimpleBooleanProperty(this, "expiredProperty", false)
|
|
||||||
var expired by expiredProperty
|
|
||||||
}
|
|
@ -1,35 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
|
||||||
*
|
|
||||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
|
||||||
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link.
|
|
||||||
*
|
|
||||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.mamoe.mirai.console.graphical.model
|
|
||||||
|
|
||||||
import javafx.beans.property.SimpleObjectProperty
|
|
||||||
import javafx.beans.property.SimpleStringProperty
|
|
||||||
import tornadofx.ItemViewModel
|
|
||||||
import tornadofx.getValue
|
|
||||||
import tornadofx.setValue
|
|
||||||
|
|
||||||
class VerificationCode(data: ByteArray = ByteArray(0)) {
|
|
||||||
val codeProperty = SimpleStringProperty(null)
|
|
||||||
var code: String? by codeProperty
|
|
||||||
|
|
||||||
val dataProperty: SimpleObjectProperty<ByteArray> = SimpleObjectProperty()
|
|
||||||
val data: ByteArray by dataProperty
|
|
||||||
|
|
||||||
init {
|
|
||||||
dataProperty.set(data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class VerificationCodeModel(code: VerificationCode) : ItemViewModel<VerificationCode>(code) {
|
|
||||||
constructor() : this(VerificationCode())
|
|
||||||
|
|
||||||
val code = bind(VerificationCode::codeProperty)
|
|
||||||
val data = bind(VerificationCode::dataProperty)
|
|
||||||
}
|
|
@ -1,72 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
|
||||||
*
|
|
||||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
|
||||||
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link.
|
|
||||||
*
|
|
||||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.mamoe.mirai.console.graphical.stylesheet
|
|
||||||
|
|
||||||
import javafx.scene.layout.BackgroundRepeat
|
|
||||||
import javafx.scene.paint.Color
|
|
||||||
import net.mamoe.mirai.console.MiraiConsole
|
|
||||||
import tornadofx.Stylesheet
|
|
||||||
import tornadofx.cssclass
|
|
||||||
import tornadofx.csselement
|
|
||||||
import java.io.File
|
|
||||||
import kotlin.random.Random
|
|
||||||
|
|
||||||
open class BaseStyleSheet : Stylesheet() {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val primaryColor = "0EA987"
|
|
||||||
const val stressColor = "35867C"
|
|
||||||
const val secondaryColor = "32CABA"
|
|
||||||
const val lightColor ="9FD1CC"
|
|
||||||
const val fontColor = "FFFFFF"
|
|
||||||
val TRANSPARENT: Color = Color.TRANSPARENT
|
|
||||||
|
|
||||||
val rootPane by cssclass("root-pane")
|
|
||||||
val jfxTabPane by cssclass("jfx-tab-pane")
|
|
||||||
val myButtonBar by cssclass("my-button-bar")
|
|
||||||
|
|
||||||
val vBox by csselement("VBox")
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
|
||||||
|
|
||||||
rootPane {
|
|
||||||
|
|
||||||
child(imageView) {}
|
|
||||||
|
|
||||||
|
|
||||||
jfxTabPane {
|
|
||||||
val bg = File(MiraiConsole.path, "background")
|
|
||||||
if (!bg.exists()) bg.mkdir()
|
|
||||||
if (bg.isDirectory) {
|
|
||||||
bg.listFiles()!!.filter { file -> file.extension in listOf("jpg", "jpeg", "png", "gif") }
|
|
||||||
.randomElement()?.also {
|
|
||||||
backgroundImage += it.toURI()
|
|
||||||
backgroundRepeat += BackgroundRepeat.REPEAT to BackgroundRepeat.REPEAT
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
listView {
|
|
||||||
backgroundColor += TRANSPARENT
|
|
||||||
|
|
||||||
listCell {
|
|
||||||
backgroundColor += TRANSPARENT
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T> Collection<T>.randomElement(): T? {
|
|
||||||
if (isEmpty())
|
|
||||||
return null
|
|
||||||
return elementAt(Random.nextInt(size))
|
|
||||||
}
|
|
@ -1,65 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
|
||||||
*
|
|
||||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
|
||||||
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link.
|
|
||||||
*
|
|
||||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.mamoe.mirai.console.graphical.stylesheet
|
|
||||||
|
|
||||||
import javafx.scene.Cursor
|
|
||||||
import javafx.scene.effect.BlurType
|
|
||||||
import javafx.scene.effect.DropShadow
|
|
||||||
import javafx.scene.paint.Color
|
|
||||||
import javafx.scene.text.FontWeight
|
|
||||||
import tornadofx.box
|
|
||||||
import tornadofx.c
|
|
||||||
import tornadofx.csselement
|
|
||||||
import tornadofx.px
|
|
||||||
|
|
||||||
class LoginViewStyleSheet : BaseStyleSheet() {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
val vBox by csselement("VBox")
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
|
||||||
|
|
||||||
/*
|
|
||||||
* center box
|
|
||||||
*/
|
|
||||||
vBox {
|
|
||||||
maxWidth = 500.px
|
|
||||||
maxHeight = 500.px
|
|
||||||
|
|
||||||
backgroundColor += c(primaryColor, 0.3)
|
|
||||||
backgroundRadius += box(15.px)
|
|
||||||
|
|
||||||
padding = box(50.px, 100.px)
|
|
||||||
spacing = 25.px
|
|
||||||
|
|
||||||
borderRadius += box(15.px)
|
|
||||||
effect = DropShadow(BlurType.THREE_PASS_BOX, Color.GRAY, 10.0, 0.0, 15.0, 15.0)
|
|
||||||
}
|
|
||||||
|
|
||||||
textField {
|
|
||||||
prefHeight = 30.px
|
|
||||||
textFill = Color.BLACK
|
|
||||||
fontWeight = FontWeight.BOLD
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* login button
|
|
||||||
*/
|
|
||||||
button {
|
|
||||||
backgroundColor += c(stressColor, 0.8)
|
|
||||||
padding = box(10.px, 0.px)
|
|
||||||
prefWidth = 500.px
|
|
||||||
textFill = Color.WHITE
|
|
||||||
fontWeight = FontWeight.BOLD
|
|
||||||
cursor = Cursor.HAND
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,70 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
|
||||||
*
|
|
||||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
|
||||||
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link.
|
|
||||||
*
|
|
||||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.mamoe.mirai.console.graphical.stylesheet
|
|
||||||
|
|
||||||
import javafx.geometry.Pos
|
|
||||||
import javafx.scene.paint.Color
|
|
||||||
import javafx.scene.text.FontWeight
|
|
||||||
import tornadofx.box
|
|
||||||
import tornadofx.c
|
|
||||||
import tornadofx.cssclass
|
|
||||||
import tornadofx.px
|
|
||||||
|
|
||||||
class PluginViewStyleSheet : BaseStyleSheet() {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
val jfxTreeTableView by cssclass("jfx-tree-table-view")
|
|
||||||
val treeTableRowCell by cssclass("tree-table-row-cell")
|
|
||||||
val columnHeader by cssclass("column-header")
|
|
||||||
val columnHeaderBg by cssclass("column-header-background")
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
init {
|
|
||||||
jfxTreeTableView {
|
|
||||||
backgroundColor += TRANSPARENT
|
|
||||||
|
|
||||||
columnHeader {
|
|
||||||
borderWidth += box(0.px)
|
|
||||||
|
|
||||||
label {
|
|
||||||
textFill = Color.BLACK
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
columnHeaderBg {
|
|
||||||
backgroundColor += c(lightColor, 0.4)
|
|
||||||
}
|
|
||||||
|
|
||||||
treeTableCell {
|
|
||||||
alignment = Pos.CENTER
|
|
||||||
}
|
|
||||||
|
|
||||||
treeTableRowCell {
|
|
||||||
|
|
||||||
fontWeight = FontWeight.SEMI_BOLD
|
|
||||||
|
|
||||||
|
|
||||||
backgroundColor += TRANSPARENT
|
|
||||||
|
|
||||||
and(":selected") {
|
|
||||||
backgroundColor += c(stressColor, 1.0)
|
|
||||||
}
|
|
||||||
|
|
||||||
and(":hover:filled") {
|
|
||||||
backgroundColor += c(stressColor, 0.6)
|
|
||||||
and(":selected") {
|
|
||||||
backgroundColor += c(stressColor, 1.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,195 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
|
||||||
*
|
|
||||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
|
||||||
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link.
|
|
||||||
*
|
|
||||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.mamoe.mirai.console.graphical.stylesheet
|
|
||||||
|
|
||||||
import javafx.scene.Cursor
|
|
||||||
import javafx.scene.text.FontWeight
|
|
||||||
import tornadofx.box
|
|
||||||
import tornadofx.c
|
|
||||||
import tornadofx.cssclass
|
|
||||||
import tornadofx.px
|
|
||||||
|
|
||||||
class PrimaryStyleSheet : BaseStyleSheet() {
|
|
||||||
companion object {
|
|
||||||
// window
|
|
||||||
val jfxTitle by cssclass("jfx-decorator-buttons-container")
|
|
||||||
val container by cssclass("jfx-decorator-content-container")
|
|
||||||
|
|
||||||
// jfx tab
|
|
||||||
val jfxTabHeader by cssclass("tab-header-background")
|
|
||||||
val closeButton by cssclass("tab-close-button")
|
|
||||||
|
|
||||||
// jfx list view
|
|
||||||
val leftPane by cssclass("left-pane")
|
|
||||||
val jfxListView by cssclass("jfx-list-view")
|
|
||||||
val jfxListCell by cssclass("jfx-list-cell")
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
|
||||||
/*
|
|
||||||
* window
|
|
||||||
*/
|
|
||||||
jfxTitle {
|
|
||||||
backgroundColor += c(primaryColor)
|
|
||||||
}
|
|
||||||
|
|
||||||
container {
|
|
||||||
borderColor += box(c(primaryColor))
|
|
||||||
borderWidth += box(0.px, 4.px, 4.px, 4.px)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* bot list
|
|
||||||
*/
|
|
||||||
rootPane {
|
|
||||||
leftPane {
|
|
||||||
|
|
||||||
backgroundColor += c(primaryColor)
|
|
||||||
// 这个padding有bug,十分神奇
|
|
||||||
padding = box(0.px, 4.px, 0.px, 0.px)
|
|
||||||
spacing = 4.px
|
|
||||||
|
|
||||||
jfxListView {
|
|
||||||
|
|
||||||
// placeholder
|
|
||||||
vBox {
|
|
||||||
spacing = 15.px
|
|
||||||
|
|
||||||
label {
|
|
||||||
textFill = c(fontColor)
|
|
||||||
fontWeight = FontWeight.BOLD
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
textFill = c(fontColor)
|
|
||||||
fontWeight = FontWeight.BOLD
|
|
||||||
backgroundColor += c(secondaryColor, 0.8)
|
|
||||||
padding = box(2.px, 10.px)
|
|
||||||
cursor = Cursor.HAND
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
jfxListCell {
|
|
||||||
backgroundColor += c(100, 100, 100, 0.4)
|
|
||||||
backgroundRadius += box(5.px)
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* tab pane
|
|
||||||
*/
|
|
||||||
jfxTabHeader {
|
|
||||||
backgroundColor += c(primaryColor)
|
|
||||||
}
|
|
||||||
|
|
||||||
jfxTabPane {
|
|
||||||
|
|
||||||
// 日志列表样式
|
|
||||||
vBox {
|
|
||||||
padding = box(15.px)
|
|
||||||
spacing = 15.px
|
|
||||||
}
|
|
||||||
|
|
||||||
myButtonBar {
|
|
||||||
spacing = 15.px
|
|
||||||
|
|
||||||
button {
|
|
||||||
backgroundColor += c(secondaryColor, 0.8)
|
|
||||||
padding = box(2.px, 10.px)
|
|
||||||
cursor = Cursor.HAND
|
|
||||||
textFill = c(fontColor)
|
|
||||||
fontSize = 12.px
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
listView {
|
|
||||||
// 字体在label里,大坑
|
|
||||||
label {
|
|
||||||
fontSize = 13.px
|
|
||||||
}
|
|
||||||
|
|
||||||
listCell {
|
|
||||||
|
|
||||||
and(":WARNING") {
|
|
||||||
backgroundColor += c("FFFF00", 0.3) // Yellow
|
|
||||||
}
|
|
||||||
|
|
||||||
and(":ERROR") {
|
|
||||||
backgroundColor += c("FF0000", 0.3) // Red
|
|
||||||
}
|
|
||||||
|
|
||||||
and(":selected") {
|
|
||||||
backgroundColor += c(stressColor, 1.0)
|
|
||||||
}
|
|
||||||
|
|
||||||
and(":hover:filled") {
|
|
||||||
backgroundColor += c(stressColor, 0.6)
|
|
||||||
and(":selected") {
|
|
||||||
backgroundColor += c(stressColor, 1.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 调整滚动条
|
|
||||||
scrollBar {
|
|
||||||
|
|
||||||
backgroundColor += TRANSPARENT
|
|
||||||
|
|
||||||
// 隐藏水平滚动条
|
|
||||||
and(horizontal) {
|
|
||||||
prefHeight = 0.px
|
|
||||||
s(incrementArrow, decrementArrow) { backgroundColor += TRANSPARENT }
|
|
||||||
}
|
|
||||||
|
|
||||||
and(vertical) {
|
|
||||||
thumb {
|
|
||||||
backgroundColor += c(stressColor, 0.6)
|
|
||||||
}
|
|
||||||
|
|
||||||
track {
|
|
||||||
backgroundColor += TRANSPARENT
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 去除JFoenix默认样式
|
|
||||||
tab {
|
|
||||||
and(":closable") {
|
|
||||||
borderWidth += box(0.px)
|
|
||||||
borderInsets += box(6.px, 0.px)
|
|
||||||
}
|
|
||||||
|
|
||||||
closeButton {
|
|
||||||
and(hover) { cursor = Cursor.HAND }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,64 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
|
||||||
*
|
|
||||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
|
||||||
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link.
|
|
||||||
*
|
|
||||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.mamoe.mirai.console.graphical.util
|
|
||||||
|
|
||||||
import com.jfoenix.controls.*
|
|
||||||
import com.jfoenix.controls.datamodels.treetable.RecursiveTreeObject
|
|
||||||
import javafx.beans.value.ObservableValue
|
|
||||||
import javafx.collections.ObservableList
|
|
||||||
import javafx.event.EventTarget
|
|
||||||
import javafx.scene.Node
|
|
||||||
import javafx.scene.control.ListView
|
|
||||||
import tornadofx.SortedFilteredList
|
|
||||||
import tornadofx.attachTo
|
|
||||||
import tornadofx.bind
|
|
||||||
|
|
||||||
internal fun EventTarget.jfxTabPane(op: JFXTabPane.() -> Unit = {}) = JFXTabPane().attachTo(this, op)
|
|
||||||
|
|
||||||
internal fun EventTarget.jfxButton(text: String = "", graphic: Node? = null, op: JFXButton.() -> Unit = {}) =
|
|
||||||
JFXButton(text).attachTo(this, op) {
|
|
||||||
if (graphic != null) it.graphic = graphic
|
|
||||||
it.buttonType = JFXButton.ButtonType.RAISED
|
|
||||||
}
|
|
||||||
|
|
||||||
fun EventTarget.jfxTextfield(value: String? = null, op: JFXTextField.() -> Unit = {}) =
|
|
||||||
JFXTextField().attachTo(this, op) {
|
|
||||||
if (value != null) it.text = value
|
|
||||||
}
|
|
||||||
|
|
||||||
fun EventTarget.jfxTextfield(property: ObservableValue<String>, op: JFXTextField.() -> Unit = {}) =
|
|
||||||
jfxTextfield().apply {
|
|
||||||
bind(property)
|
|
||||||
op(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun EventTarget.jfxPasswordfield(value: String? = null, op: JFXPasswordField.() -> Unit = {}) =
|
|
||||||
JFXPasswordField().attachTo(this, op) {
|
|
||||||
if (value != null) it.text = value
|
|
||||||
}
|
|
||||||
|
|
||||||
fun EventTarget.jfxPasswordfield(property: ObservableValue<String>, op: JFXPasswordField.() -> 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T : RecursiveTreeObject<T>?> EventTarget.jfxTreeTableView(
|
|
||||||
items: ObservableList<T>? = null,
|
|
||||||
op: JFXTreeTableView<T>.() -> Unit = {}
|
|
||||||
) = JFXTreeTableView<T>(RecursiveTreeItem(items, RecursiveTreeObject<T>::getChildren)).attachTo(this, op)
|
|
@ -1,24 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
|
||||||
*
|
|
||||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
|
||||||
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link.
|
|
||||||
*
|
|
||||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
|
||||||
*/
|
|
||||||
|
|
||||||
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) }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
|
||||||
*
|
|
||||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
|
||||||
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link.
|
|
||||||
*
|
|
||||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.mamoe.mirai.console.graphical.util
|
|
||||||
|
|
||||||
import javafx.event.EventTarget
|
|
||||||
import javafx.geometry.Pos
|
|
||||||
import javafx.scene.layout.HBox
|
|
||||||
import tornadofx.addClass
|
|
||||||
import tornadofx.hbox
|
|
||||||
|
|
||||||
fun EventTarget.myButtonBar(alignment: Pos = Pos.BASELINE_LEFT, op: HBox.() -> Unit = {}) = hbox {
|
|
||||||
addClass("my-button-bar")
|
|
||||||
this.alignment = alignment
|
|
||||||
op()
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
|
||||||
*
|
|
||||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
|
||||||
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link.
|
|
||||||
*
|
|
||||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.mamoe.mirai.console.graphical.view
|
|
||||||
|
|
||||||
import com.jfoenix.controls.JFXDecorator
|
|
||||||
import tornadofx.View
|
|
||||||
|
|
||||||
class Decorator : View() {
|
|
||||||
|
|
||||||
override val root = JFXDecorator(primaryStage, find<PrimaryView>().root).apply {
|
|
||||||
prefWidth = 1000.0
|
|
||||||
prefHeight = 650.0
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,59 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
|
||||||
*
|
|
||||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
|
||||||
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link.
|
|
||||||
*
|
|
||||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.mamoe.mirai.console.graphical.view
|
|
||||||
|
|
||||||
import javafx.beans.property.SimpleStringProperty
|
|
||||||
import javafx.geometry.Pos
|
|
||||||
import javafx.scene.image.Image
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import net.mamoe.mirai.console.graphical.controller.MiraiGraphicalFrontEndController
|
|
||||||
import net.mamoe.mirai.console.graphical.stylesheet.LoginViewStyleSheet
|
|
||||||
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 LoginView : View("CNM") {
|
|
||||||
|
|
||||||
private val controller = find<MiraiGraphicalFrontEndController>()
|
|
||||||
private val qq = SimpleStringProperty("")
|
|
||||||
private val psd = SimpleStringProperty("")
|
|
||||||
|
|
||||||
override val root = borderpane {
|
|
||||||
|
|
||||||
addStylesheet(LoginViewStyleSheet::class)
|
|
||||||
|
|
||||||
center = vbox {
|
|
||||||
|
|
||||||
imageview(Image(LoginView::class.java.classLoader.getResourceAsStream("character.png"))) {
|
|
||||||
alignment = Pos.CENTER
|
|
||||||
}
|
|
||||||
|
|
||||||
jfxTextfield(qq) {
|
|
||||||
promptText = "QQ"
|
|
||||||
isLabelFloat = true
|
|
||||||
}
|
|
||||||
|
|
||||||
jfxPasswordfield(psd) {
|
|
||||||
promptText = "Password"
|
|
||||||
isLabelFloat = true
|
|
||||||
}
|
|
||||||
|
|
||||||
jfxButton("Login").action {
|
|
||||||
runAsync {
|
|
||||||
runBlocking { controller.login(qq.value, psd.value) }
|
|
||||||
}.ui {
|
|
||||||
qq.value = ""
|
|
||||||
psd.value = ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,182 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
|
||||||
*
|
|
||||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
|
||||||
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link.
|
|
||||||
*
|
|
||||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.mamoe.mirai.console.graphical.view
|
|
||||||
|
|
||||||
import com.jfoenix.controls.JFXTreeTableColumn
|
|
||||||
import javafx.application.Platform
|
|
||||||
import javafx.collections.ObservableList
|
|
||||||
import javafx.geometry.Pos
|
|
||||||
import javafx.scene.control.Button
|
|
||||||
import javafx.scene.control.TreeTableCell
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import net.mamoe.mirai.console.MiraiConsole
|
|
||||||
import net.mamoe.mirai.console.graphical.controller.MiraiGraphicalFrontEndController
|
|
||||||
import net.mamoe.mirai.console.graphical.event.ReloadEvent
|
|
||||||
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 net.mamoe.mirai.console.graphical.view.dialog.PluginDetailFragment
|
|
||||||
import tornadofx.*
|
|
||||||
|
|
||||||
class PluginsCenterView : View() {
|
|
||||||
|
|
||||||
private val controller = find<MiraiGraphicalFrontEndController>()
|
|
||||||
private val center get() = MiraiConsole.frontEnd.pluginCenter
|
|
||||||
private val plugins: ObservableList<PluginModel> = observableListOf()
|
|
||||||
|
|
||||||
init {
|
|
||||||
// 监听插件重载,情况插件列表,重新载入。
|
|
||||||
// 同时把页面刷新,按键的listener也初始化
|
|
||||||
subscribe<ReloadEvent> { plugins.clear() }
|
|
||||||
}
|
|
||||||
|
|
||||||
override val root = jfxTreeTableView(plugins) {
|
|
||||||
|
|
||||||
addStylesheet(PluginViewStyleSheet::class)
|
|
||||||
|
|
||||||
placeholder = button("从崔云获取插件列表") {
|
|
||||||
action {
|
|
||||||
isDisable = true
|
|
||||||
runAsync {
|
|
||||||
fetch()
|
|
||||||
}.ui {
|
|
||||||
plugins.addAll(it)
|
|
||||||
isDisable = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
isShowRoot = false
|
|
||||||
columns.addAll(
|
|
||||||
JFXTreeTableColumn<PluginModel, String>("插件名").apply {
|
|
||||||
prefWidthProperty().bind(this@jfxTreeTableView.widthProperty().multiply(0.1))
|
|
||||||
|
|
||||||
setCellValueFactory {
|
|
||||||
return@setCellValueFactory it.value.value.nameProperty
|
|
||||||
}
|
|
||||||
},
|
|
||||||
JFXTreeTableColumn<PluginModel, String>("版本").apply {
|
|
||||||
prefWidthProperty().bind(this@jfxTreeTableView.widthProperty().multiply(0.1))
|
|
||||||
|
|
||||||
setCellValueFactory {
|
|
||||||
return@setCellValueFactory it.value.value.versionProperty
|
|
||||||
}
|
|
||||||
},
|
|
||||||
JFXTreeTableColumn<PluginModel, String>("作者").apply {
|
|
||||||
prefWidthProperty().bind(this@jfxTreeTableView.widthProperty().multiply(0.1))
|
|
||||||
|
|
||||||
setCellValueFactory {
|
|
||||||
return@setCellValueFactory it.value.value.authorProperty
|
|
||||||
}
|
|
||||||
},
|
|
||||||
JFXTreeTableColumn<PluginModel, String>("介绍").apply {
|
|
||||||
prefWidthProperty().bind(this@jfxTreeTableView.widthProperty().multiply(0.48))
|
|
||||||
|
|
||||||
setCellValueFactory {
|
|
||||||
return@setCellValueFactory it.value.value.descriptionProperty
|
|
||||||
}
|
|
||||||
},
|
|
||||||
JFXTreeTableColumn<PluginModel, PluginModel>("操作").apply {
|
|
||||||
prefWidthProperty().bind(this@jfxTreeTableView.widthProperty().multiply(0.2))
|
|
||||||
|
|
||||||
setCellValueFactory { return@setCellValueFactory it.value.valueProperty() }
|
|
||||||
|
|
||||||
setCellFactory {
|
|
||||||
return@setCellFactory object : TreeTableCell<PluginModel, PluginModel>() {
|
|
||||||
override fun updateItem(item: PluginModel?, empty: Boolean) {
|
|
||||||
if (item != null && !empty) {
|
|
||||||
graphic = hbox {
|
|
||||||
|
|
||||||
spacing = 15.0
|
|
||||||
alignment = Pos.CENTER
|
|
||||||
|
|
||||||
jfxButton("详情") {
|
|
||||||
action { detail(item) }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
jfxButton(if (item.expired) "更新" else "下载") {
|
|
||||||
action { download(item, this) }
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
text = ""
|
|
||||||
} else {
|
|
||||||
graphic = null
|
|
||||||
text = ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun fetch(): List<PluginModel> = mutableListOf<PluginModel>().apply {
|
|
||||||
runBlocking {
|
|
||||||
var page = 1
|
|
||||||
while (true) {
|
|
||||||
val map = center.fetchPlugin(page++)
|
|
||||||
if (map.isEmpty()) return@runBlocking
|
|
||||||
map.forEach {
|
|
||||||
with(
|
|
||||||
PluginModel(
|
|
||||||
it.value.name,
|
|
||||||
it.value.version,
|
|
||||||
it.value.author,
|
|
||||||
it.value.description,
|
|
||||||
it.value
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
add(this)
|
|
||||||
controller.checkUpdate(this)
|
|
||||||
controller.checkAmbiguous(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun detail(pluginModel: PluginModel) {
|
|
||||||
runAsync {
|
|
||||||
runBlocking { center.findPlugin(pluginModel.name) }
|
|
||||||
}.ui {
|
|
||||||
it?.apply {
|
|
||||||
PluginDetailFragment(this).openModal()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun download(pluginModel: PluginModel, button: Button) {
|
|
||||||
button.isDisable = true
|
|
||||||
button.text = "连接中..."
|
|
||||||
runAsync {
|
|
||||||
runBlocking {
|
|
||||||
center.downloadPlugin(pluginModel.name) {
|
|
||||||
// download process
|
|
||||||
Platform.runLater {
|
|
||||||
button.text = "$it%"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.ui {
|
|
||||||
with(button) {
|
|
||||||
isDisable = false
|
|
||||||
text = "重载插件"
|
|
||||||
setOnAction {
|
|
||||||
controller.reloadPlugins()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,87 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
|
||||||
*
|
|
||||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
|
||||||
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link.
|
|
||||||
*
|
|
||||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.mamoe.mirai.console.graphical.view
|
|
||||||
|
|
||||||
import com.jfoenix.controls.JFXTreeTableColumn
|
|
||||||
import javafx.scene.control.TreeTableCell
|
|
||||||
import net.mamoe.mirai.console.graphical.controller.MiraiGraphicalFrontEndController
|
|
||||||
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.View
|
|
||||||
import tornadofx.addStylesheet
|
|
||||||
import tornadofx.visibleWhen
|
|
||||||
|
|
||||||
class PluginsView : View() {
|
|
||||||
|
|
||||||
private val controller = find<MiraiGraphicalFrontEndController>()
|
|
||||||
val plugins = controller.pluginList
|
|
||||||
|
|
||||||
override val root = jfxTreeTableView(plugins) {
|
|
||||||
|
|
||||||
addStylesheet(PluginViewStyleSheet::class)
|
|
||||||
|
|
||||||
isShowRoot = false
|
|
||||||
columns.addAll(
|
|
||||||
JFXTreeTableColumn<PluginModel, String>("插件名").apply {
|
|
||||||
prefWidthProperty().bind(this@jfxTreeTableView.widthProperty().multiply(0.1))
|
|
||||||
|
|
||||||
setCellValueFactory {
|
|
||||||
return@setCellValueFactory it.value.value.nameProperty
|
|
||||||
}
|
|
||||||
},
|
|
||||||
JFXTreeTableColumn<PluginModel, String>("版本").apply {
|
|
||||||
prefWidthProperty().bind(this@jfxTreeTableView.widthProperty().multiply(0.1))
|
|
||||||
|
|
||||||
setCellValueFactory {
|
|
||||||
return@setCellValueFactory it.value.value.versionProperty
|
|
||||||
}
|
|
||||||
},
|
|
||||||
JFXTreeTableColumn<PluginModel, String>("作者").apply {
|
|
||||||
prefWidthProperty().bind(this@jfxTreeTableView.widthProperty().multiply(0.1))
|
|
||||||
|
|
||||||
setCellValueFactory {
|
|
||||||
return@setCellValueFactory it.value.value.authorProperty
|
|
||||||
}
|
|
||||||
},
|
|
||||||
JFXTreeTableColumn<PluginModel, String>("介绍").apply {
|
|
||||||
prefWidthProperty().bind(this@jfxTreeTableView.widthProperty().multiply(0.6))
|
|
||||||
|
|
||||||
setCellValueFactory {
|
|
||||||
return@setCellValueFactory it.value.value.descriptionProperty
|
|
||||||
}
|
|
||||||
},
|
|
||||||
JFXTreeTableColumn<PluginModel, PluginModel>("操作").apply {
|
|
||||||
prefWidthProperty().bind(this@jfxTreeTableView.widthProperty().multiply(0.08))
|
|
||||||
|
|
||||||
setCellValueFactory { return@setCellValueFactory it.value.valueProperty() }
|
|
||||||
|
|
||||||
setCellFactory {
|
|
||||||
return@setCellFactory object : TreeTableCell<PluginModel, PluginModel>() {
|
|
||||||
override fun updateItem(item: PluginModel?, empty: Boolean) {
|
|
||||||
if (item != null && !empty) {
|
|
||||||
graphic = jfxButton("更新") {
|
|
||||||
visibleWhen(item.expiredProperty)
|
|
||||||
|
|
||||||
// to do update
|
|
||||||
}
|
|
||||||
text = ""
|
|
||||||
} else {
|
|
||||||
graphic = null
|
|
||||||
text = ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,220 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
|
||||||
*
|
|
||||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
|
||||||
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link.
|
|
||||||
*
|
|
||||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.mamoe.mirai.console.graphical.view
|
|
||||||
|
|
||||||
import com.jfoenix.controls.JFXButton
|
|
||||||
import com.jfoenix.controls.JFXListCell
|
|
||||||
import javafx.collections.ObservableList
|
|
||||||
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.Clipboard
|
|
||||||
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.MiraiGraphicalFrontEndController
|
|
||||||
import net.mamoe.mirai.console.graphical.model.BotModel
|
|
||||||
import net.mamoe.mirai.console.graphical.util.*
|
|
||||||
import tornadofx.*
|
|
||||||
|
|
||||||
class PrimaryView : View() {
|
|
||||||
|
|
||||||
private val controller = find<MiraiGraphicalFrontEndController>()
|
|
||||||
private lateinit var mainTabPane: TabPane
|
|
||||||
|
|
||||||
override val root = borderpane {
|
|
||||||
|
|
||||||
addClass("root-pane")
|
|
||||||
|
|
||||||
left = vbox {
|
|
||||||
|
|
||||||
addClass("left-pane")
|
|
||||||
|
|
||||||
imageview(Image(PrimaryView::class.java.classLoader.getResourceAsStream("logo.png"))) {
|
|
||||||
fitHeight = 40.0
|
|
||||||
alignment = Pos.CENTER
|
|
||||||
isPreserveRatio = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// bot list
|
|
||||||
jfxListView(controller.botList) {
|
|
||||||
fitToParentHeight()
|
|
||||||
|
|
||||||
placeholder = vbox {
|
|
||||||
|
|
||||||
alignment = Pos.CENTER
|
|
||||||
|
|
||||||
label("Bot列表为空,请登录一个Bot")
|
|
||||||
|
|
||||||
jfxButton("登录") {
|
|
||||||
buttonType = JFXButton.ButtonType.FLAT
|
|
||||||
}.action {
|
|
||||||
// select login pane
|
|
||||||
mainTabPane.selectionModel.selectLast()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setCellFactory {
|
|
||||||
object : JFXListCell<BotModel>() {
|
|
||||||
var tab: Tab? = null
|
|
||||||
|
|
||||||
init {
|
|
||||||
onDoubleClick {
|
|
||||||
tab?.select() ?: mainTabPane.logTab(
|
|
||||||
text = item.uin.toString(),
|
|
||||||
logs = item.logHistory
|
|
||||||
).select().also { tab = it }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun updateItem(item: BotModel?, empty: Boolean) {
|
|
||||||
super.updateItem(item, empty)
|
|
||||||
if (item != null && !empty) {
|
|
||||||
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 = ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
center = vbox {
|
|
||||||
|
|
||||||
jfxTabPane {
|
|
||||||
|
|
||||||
fitToParentHeight()
|
|
||||||
|
|
||||||
tabClosingPolicy = TabPane.TabClosingPolicy.ALL_TABS
|
|
||||||
|
|
||||||
logTab("Main", controller.mainLog, closeable = false)
|
|
||||||
|
|
||||||
fixedTab("Plugins").content = find<PluginsView>().root
|
|
||||||
|
|
||||||
fixedTab("Plugins Center").content = find<PluginsCenterView>().root
|
|
||||||
|
|
||||||
fixedTab("Settings").content = find<SettingsView>().root
|
|
||||||
|
|
||||||
fixedTab("Login").content = find<LoginView>().root
|
|
||||||
|
|
||||||
mainTabPane = this
|
|
||||||
}
|
|
||||||
|
|
||||||
// command input
|
|
||||||
textfield {
|
|
||||||
|
|
||||||
promptText = "在这里输出命令"
|
|
||||||
|
|
||||||
setOnKeyPressed {
|
|
||||||
if (it.code == KeyCode.ENTER) {
|
|
||||||
runAsync {
|
|
||||||
runBlocking { controller.sendCommand(text) }
|
|
||||||
}.ui { text = "" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun Tab.select() = apply {
|
|
||||||
if (!mainTabPane.tabs.contains(this)) mainTabPane.tabs.add(this)
|
|
||||||
mainTabPane.selectionModel.select(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun TabPane.fixedTab(title: String) = tab(title) { isClosable = false }
|
|
||||||
|
|
||||||
private fun TabPane.logTab(
|
|
||||||
text: String? = null,
|
|
||||||
logs: ObservableList<Pair<String, String>>,
|
|
||||||
closeable: Boolean = true,
|
|
||||||
op: Tab.() -> Unit = {}
|
|
||||||
) = tab(text) {
|
|
||||||
|
|
||||||
this.isClosable = closeable
|
|
||||||
|
|
||||||
vbox {
|
|
||||||
myButtonBar(alignment = Pos.BASELINE_RIGHT) {
|
|
||||||
|
|
||||||
jfxButton("导出日志").action {
|
|
||||||
val path = chooseFile(
|
|
||||||
"选择保存路径",
|
|
||||||
arrayOf(FileChooser.ExtensionFilter("日志", "txt")),
|
|
||||||
FileChooserMode.Save,
|
|
||||||
owner = FX.primaryStage
|
|
||||||
) {
|
|
||||||
initialFileName = "$text.txt"
|
|
||||||
}
|
|
||||||
runAsyncWithOverlay {
|
|
||||||
path.firstOrNull()?.run {
|
|
||||||
if (!exists()) createNewFile()
|
|
||||||
writer().use {
|
|
||||||
logs.forEach { log -> it.appendln(log.first) }
|
|
||||||
}
|
|
||||||
true
|
|
||||||
} ?: false
|
|
||||||
}.ui {// isSucceed: Boolean ->
|
|
||||||
// notify something
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
listview(logs) {
|
|
||||||
|
|
||||||
fitToParentSize()
|
|
||||||
cellFormat {
|
|
||||||
|
|
||||||
addPseudoClass(it.second)
|
|
||||||
|
|
||||||
graphic = label(it.first) {
|
|
||||||
maxWidthProperty().bind(this@listview.widthProperty())
|
|
||||||
isWrapText = true
|
|
||||||
|
|
||||||
|
|
||||||
contextmenu {
|
|
||||||
item("复制").action {
|
|
||||||
Clipboard.getSystemClipboard().putString(it.first)
|
|
||||||
}
|
|
||||||
item("删除").action {
|
|
||||||
logs.remove(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
also(op)
|
|
||||||
}
|
|
@ -1,68 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
|
||||||
*
|
|
||||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
|
||||||
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link.
|
|
||||||
*
|
|
||||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.mamoe.mirai.console.graphical.view
|
|
||||||
|
|
||||||
import javafx.geometry.Pos
|
|
||||||
import net.mamoe.mirai.console.graphical.controller.MiraiGraphicalFrontEndController
|
|
||||||
import net.mamoe.mirai.console.graphical.model.GlobalSettingModel
|
|
||||||
import net.mamoe.mirai.console.graphical.util.jfxButton
|
|
||||||
import net.mamoe.mirai.console.graphical.util.jfxTextfield
|
|
||||||
import net.mamoe.mirai.console.graphical.util.myButtonBar
|
|
||||||
import tornadofx.*
|
|
||||||
import java.awt.Desktop
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
class SettingsView : View() {
|
|
||||||
|
|
||||||
private val controller = find<MiraiGraphicalFrontEndController>()
|
|
||||||
private val settingModel = find<GlobalSettingModel>()
|
|
||||||
|
|
||||||
override val root = vbox {
|
|
||||||
|
|
||||||
myButtonBar(alignment = Pos.BASELINE_RIGHT) {
|
|
||||||
jfxButton("撤掉").action {
|
|
||||||
settingModel.rollback()
|
|
||||||
}
|
|
||||||
jfxButton("保存").action {
|
|
||||||
settingModel.commit()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
form {
|
|
||||||
fieldset("插件目录") {
|
|
||||||
field {
|
|
||||||
jfxTextfield((System.getProperty("user.dir") + "/plugins/").replace("//", "/")) { isEditable = false }
|
|
||||||
jfxButton("打开目录").action {
|
|
||||||
(System.getProperty("user.dir") + "/plugins/").replace("//", "/").also { path ->
|
|
||||||
Desktop.getDesktop().takeIf { it.isSupported(Desktop.Action.OPEN) }?.open(File(path))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fieldset("背景目录") {
|
|
||||||
field {
|
|
||||||
jfxTextfield((System.getProperty("user.dir") + "/background/").replace("//", "/")) { isEditable = false }
|
|
||||||
jfxButton("打开目录").action {
|
|
||||||
(System.getProperty("user.dir") + "/background/").replace("//", "/").also { path ->
|
|
||||||
Desktop.getDesktop().takeIf { it.isSupported(Desktop.Action.OPEN) }?.open(File(path))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fieldset("最大日志容量") {
|
|
||||||
field {
|
|
||||||
jfxTextfield().bind(settingModel.maxLogNum)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,48 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
|
||||||
*
|
|
||||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
|
||||||
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link.
|
|
||||||
*
|
|
||||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.mamoe.mirai.console.graphical.view.dialog
|
|
||||||
|
|
||||||
import javafx.scene.control.TextField
|
|
||||||
import javafx.stage.Modality
|
|
||||||
import javafx.stage.StageStyle
|
|
||||||
import tornadofx.*
|
|
||||||
|
|
||||||
class InputDialog(title: String) : Fragment() {
|
|
||||||
|
|
||||||
private lateinit var input: TextField
|
|
||||||
|
|
||||||
init {
|
|
||||||
titleProperty.value = title
|
|
||||||
}
|
|
||||||
|
|
||||||
override val root = form {
|
|
||||||
|
|
||||||
fieldset {
|
|
||||||
field(title) {
|
|
||||||
input = textfield("")
|
|
||||||
}
|
|
||||||
|
|
||||||
buttonbar {
|
|
||||||
|
|
||||||
button("提交").action { close() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun open(): String {
|
|
||||||
// 阻塞窗口直到关闭
|
|
||||||
openModal(
|
|
||||||
stageStyle = StageStyle.DECORATED,
|
|
||||||
modality = Modality.APPLICATION_MODAL,
|
|
||||||
block = true
|
|
||||||
)
|
|
||||||
return input.text
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,85 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
|
||||||
*
|
|
||||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
|
||||||
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link.
|
|
||||||
*
|
|
||||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.mamoe.mirai.console.graphical.view.dialog
|
|
||||||
|
|
||||||
import javafx.geometry.Insets
|
|
||||||
import net.mamoe.mirai.console.center.PluginCenter
|
|
||||||
import net.mamoe.mirai.console.graphical.util.jfxTextfield
|
|
||||||
import tornadofx.Fragment
|
|
||||||
import tornadofx.vbox
|
|
||||||
|
|
||||||
class PluginDetailFragment(info: PluginCenter.PluginInfo) : Fragment() {
|
|
||||||
|
|
||||||
init {
|
|
||||||
title = info.name
|
|
||||||
}
|
|
||||||
|
|
||||||
override val root = vbox {
|
|
||||||
|
|
||||||
prefWidth = 450.0
|
|
||||||
padding = Insets(25.0)
|
|
||||||
spacing = 25.0
|
|
||||||
|
|
||||||
jfxTextfield(info.name) {
|
|
||||||
promptText = "插件名"
|
|
||||||
isLabelFloat = true
|
|
||||||
}
|
|
||||||
|
|
||||||
jfxTextfield(info.version) {
|
|
||||||
promptText = "版本号"
|
|
||||||
isLabelFloat = true
|
|
||||||
}
|
|
||||||
|
|
||||||
jfxTextfield(info.coreVersion) {
|
|
||||||
promptText = "Mirai核心版本"
|
|
||||||
isLabelFloat = true
|
|
||||||
}
|
|
||||||
|
|
||||||
jfxTextfield(info.consoleVersion) {
|
|
||||||
promptText = "Mirai控制台版本"
|
|
||||||
isLabelFloat = true
|
|
||||||
}
|
|
||||||
|
|
||||||
jfxTextfield(info.tags.joinToString(",")) {
|
|
||||||
promptText = "标签"
|
|
||||||
isLabelFloat = true
|
|
||||||
}
|
|
||||||
|
|
||||||
jfxTextfield(info.author) {
|
|
||||||
promptText = "作者"
|
|
||||||
isLabelFloat = true
|
|
||||||
}
|
|
||||||
|
|
||||||
jfxTextfield(info.description) {
|
|
||||||
promptText = "描述"
|
|
||||||
isLabelFloat = true
|
|
||||||
}
|
|
||||||
|
|
||||||
jfxTextfield(info.usage) {
|
|
||||||
promptText = "使用方法"
|
|
||||||
isLabelFloat = true
|
|
||||||
}
|
|
||||||
|
|
||||||
jfxTextfield(info.vcs) {
|
|
||||||
promptText = "仓库地址"
|
|
||||||
isLabelFloat = true
|
|
||||||
}
|
|
||||||
|
|
||||||
jfxTextfield(info.commands.joinToString("\n\n")) {
|
|
||||||
promptText = "命令"
|
|
||||||
isLabelFloat = true
|
|
||||||
}
|
|
||||||
|
|
||||||
jfxTextfield(info.changeLog.joinToString("\n\n")) {
|
|
||||||
promptText = "修改日志"
|
|
||||||
isLabelFloat = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,50 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
|
||||||
*
|
|
||||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
|
||||||
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link.
|
|
||||||
*
|
|
||||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
|
||||||
*/
|
|
||||||
|
|
||||||
package net.mamoe.mirai.console.graphical.view.dialog
|
|
||||||
|
|
||||||
import javafx.scene.image.Image
|
|
||||||
import net.mamoe.mirai.console.graphical.model.VerificationCodeModel
|
|
||||||
import tornadofx.*
|
|
||||||
import java.io.ByteArrayInputStream
|
|
||||||
|
|
||||||
class VerificationCodeFragment : Fragment() {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
val MAGIC_KEY = String("CANCEL".toByteArray())
|
|
||||||
}
|
|
||||||
|
|
||||||
val code = find<VerificationCodeModel>()
|
|
||||||
|
|
||||||
override val root = vbox {
|
|
||||||
// 显示验证码
|
|
||||||
imageview(Image(ByteArrayInputStream(code.data.value)))
|
|
||||||
|
|
||||||
form {
|
|
||||||
fieldset {
|
|
||||||
field("验证码") {
|
|
||||||
textfield(code.code)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
buttonbar {
|
|
||||||
button("提交").action {
|
|
||||||
code.commit()
|
|
||||||
this@VerificationCodeFragment.close()
|
|
||||||
}
|
|
||||||
button("取消").action {
|
|
||||||
code.code.value =
|
|
||||||
MAGIC_KEY
|
|
||||||
code.commit()
|
|
||||||
this@VerificationCodeFragment.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
import net.mamoe.mirai.console.graphical.MiraiGraphicalUI
|
|
||||||
import tornadofx.launch
|
|
||||||
|
|
||||||
fun main(args: Array<String>) {
|
|
||||||
launch<MiraiGraphicalUI>(args)
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user