2023-07-01 04:12:19 +08:00
|
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
|
|
|
|
import QtQuick
|
|
|
|
import QtQuick.Layouts
|
|
|
|
import QtQuick.Controls
|
2024-07-03 01:31:22 +08:00
|
|
|
import Fk
|
2023-07-01 04:12:19 +08:00
|
|
|
|
|
|
|
Item {
|
|
|
|
id: root
|
|
|
|
anchors.fill: parent
|
2024-07-03 01:31:22 +08:00
|
|
|
property var selectedServer: serverModel.get(serverList.currentIndex)
|
2023-07-01 04:12:19 +08:00
|
|
|
|
|
|
|
Timer {
|
|
|
|
id: opTimer
|
|
|
|
interval: 5000
|
|
|
|
}
|
|
|
|
|
|
|
|
Component {
|
|
|
|
id: serverDelegate
|
|
|
|
|
|
|
|
Item {
|
|
|
|
height: 64
|
2024-07-03 01:31:22 +08:00
|
|
|
width: serverList.width / 2 - 4
|
2023-07-01 04:12:19 +08:00
|
|
|
|
|
|
|
RowLayout {
|
|
|
|
anchors.fill: parent
|
|
|
|
spacing: 16
|
|
|
|
|
2024-07-03 01:31:22 +08:00
|
|
|
Item {}
|
|
|
|
|
2023-07-01 04:12:19 +08:00
|
|
|
Image {
|
2024-07-03 01:31:22 +08:00
|
|
|
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
|
|
|
|
Layout.preferredHeight: 56
|
|
|
|
Layout.preferredWidth: 56
|
2023-07-01 04:12:19 +08:00
|
|
|
fillMode: Image.PreserveAspectFit
|
2024-07-03 01:31:22 +08:00
|
|
|
source: {
|
|
|
|
if (!favicon) return SkinBank.MISC_DIR + "server_icon";
|
|
|
|
if (favicon === "default") return AppPath + "/image/icon.png";
|
|
|
|
return favicon;
|
|
|
|
}
|
2023-07-01 04:12:19 +08:00
|
|
|
}
|
|
|
|
|
2023-07-01 23:14:30 +08:00
|
|
|
ColumnLayout {
|
|
|
|
Layout.fillWidth: true
|
|
|
|
Text {
|
|
|
|
Layout.fillWidth: true
|
|
|
|
horizontalAlignment: Text.AlignLeft
|
2024-07-03 01:31:22 +08:00
|
|
|
text: {
|
|
|
|
if (name) return name;
|
|
|
|
let a = addr;
|
|
|
|
let p = port;
|
|
|
|
if (p === 9527) p = 0;
|
|
|
|
if (a.includes(":") && p) { // IPv6
|
|
|
|
a = `[${a}]`;
|
|
|
|
}
|
|
|
|
if (p) {
|
|
|
|
p = `:${p}`;
|
|
|
|
} else {
|
|
|
|
p = "";
|
|
|
|
}
|
|
|
|
return `${a}${p}`;
|
|
|
|
}
|
2023-07-01 23:14:30 +08:00
|
|
|
font.bold: true
|
2024-07-03 01:31:22 +08:00
|
|
|
color: favicon ? "black" : "gray"
|
2023-07-01 23:14:30 +08:00
|
|
|
}
|
2023-07-01 04:12:19 +08:00
|
|
|
|
2023-07-01 23:14:30 +08:00
|
|
|
Text {
|
|
|
|
Layout.fillWidth: true
|
|
|
|
horizontalAlignment: Text.AlignLeft
|
2024-07-03 01:31:22 +08:00
|
|
|
text: delay + " ms " + misMatchMsg
|
2023-07-01 23:14:30 +08:00
|
|
|
textFormat: TextEdit.RichText
|
2024-07-03 01:31:22 +08:00
|
|
|
color: {
|
|
|
|
if (delay < 0) {
|
|
|
|
return "gray";
|
|
|
|
} else if (delay >= 0 && delay < 100) {
|
|
|
|
return "green";
|
|
|
|
} else if (delay >= 100 && delay < 500) {
|
|
|
|
return "orange";
|
|
|
|
} else {
|
|
|
|
return "red";
|
|
|
|
}
|
|
|
|
}
|
2023-07-01 23:14:30 +08:00
|
|
|
}
|
2023-07-01 04:12:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Text {
|
2024-07-03 01:31:22 +08:00
|
|
|
text: online + "/<font size='1'>" + capacity + "</font>"
|
|
|
|
font.pixelSize: 26
|
|
|
|
color: favicon ? "black" : "gray"
|
2023-07-01 04:12:19 +08:00
|
|
|
}
|
2024-07-03 01:31:22 +08:00
|
|
|
|
|
|
|
Item {}
|
2023-07-01 04:12:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
TapHandler {
|
|
|
|
onTapped: {
|
|
|
|
if (serverList.currentIndex === index) {
|
|
|
|
serverList.currentIndex = -1;
|
|
|
|
} else {
|
|
|
|
serverList.currentIndex = index;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-03 01:31:22 +08:00
|
|
|
ColumnLayout {
|
|
|
|
x: 6
|
|
|
|
height: parent.height
|
|
|
|
Item { Layout.fillHeight: true }
|
|
|
|
Image {
|
|
|
|
Layout.preferredWidth: 24; Layout.preferredHeight: 23
|
|
|
|
source: SkinBank.MISC_DIR + "network_local"
|
|
|
|
visible: lan
|
|
|
|
}
|
|
|
|
Image {
|
|
|
|
Layout.preferredWidth: 24; Layout.preferredHeight: 23
|
|
|
|
source: SkinBank.MISC_DIR + "favorite"
|
|
|
|
visible: favorite
|
|
|
|
}
|
2023-07-01 04:12:19 +08:00
|
|
|
}
|
|
|
|
}
|
2024-07-03 01:31:22 +08:00
|
|
|
}
|
2023-07-01 04:12:19 +08:00
|
|
|
|
2024-07-03 01:31:22 +08:00
|
|
|
RowLayout {
|
|
|
|
id: serverListBar
|
|
|
|
height: childrenRect.height
|
|
|
|
width: serverList.width
|
|
|
|
Text {
|
|
|
|
text: "已收藏服务器与公共服务器列表"
|
|
|
|
font.pixelSize: 18
|
|
|
|
x: 32; y: 8
|
2023-07-01 04:12:19 +08:00
|
|
|
}
|
2024-07-03 01:31:22 +08:00
|
|
|
Item { Layout.fillWidth: true }
|
2023-07-01 04:12:19 +08:00
|
|
|
Button {
|
|
|
|
text: qsTr("Refresh List")
|
|
|
|
enabled: !opTimer.running
|
|
|
|
onClicked: {
|
|
|
|
opTimer.start();
|
|
|
|
for (let i = 0; i < serverModel.count; i++) {
|
|
|
|
const item = serverModel.get(i);
|
2024-07-03 01:31:22 +08:00
|
|
|
if (!item.favorite && !item.lan) break;
|
|
|
|
item.delayBegin = (new Date).getTime();
|
|
|
|
Backend.getServerInfo(item.addr, item.port);
|
2023-07-01 04:12:19 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Button {
|
|
|
|
text: qsTr("Detect LAN")
|
|
|
|
enabled: !opTimer.running
|
|
|
|
onClicked: {
|
|
|
|
opTimer.start();
|
|
|
|
Backend.detectServer();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Button {
|
|
|
|
text: qsTr("Go Back")
|
|
|
|
onClicked: serverDialog.hide();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-03 01:31:22 +08:00
|
|
|
ColumnLayout {
|
|
|
|
id: serverPanel
|
|
|
|
anchors.right: parent.right
|
|
|
|
anchors.top: parent.top
|
|
|
|
anchors.margins: 8
|
|
|
|
height: parent.height - 16
|
|
|
|
width: parent.width * 0.3
|
|
|
|
TextField {
|
|
|
|
id: addressEdit
|
|
|
|
maximumLength: 64
|
|
|
|
Layout.fillWidth: true
|
|
|
|
placeholderText: "服务器地址"
|
|
|
|
text: selectedServer?.addr ?? ""
|
2023-07-01 04:12:19 +08:00
|
|
|
}
|
2024-07-03 01:31:22 +08:00
|
|
|
TextField {
|
|
|
|
id: portEdit
|
|
|
|
maximumLength: 6
|
|
|
|
Layout.fillWidth: true
|
|
|
|
placeholderText: "端口"
|
|
|
|
text: selectedServer?.port ?? ""
|
|
|
|
}
|
|
|
|
Flickable {
|
|
|
|
Layout.fillHeight: true
|
|
|
|
Layout.fillWidth: true
|
|
|
|
contentHeight: descText.height
|
|
|
|
clip: true
|
2023-07-01 04:12:19 +08:00
|
|
|
Text {
|
2024-07-03 01:31:22 +08:00
|
|
|
id: descText
|
|
|
|
width: parent.width
|
|
|
|
text: selectedServer?.description ?? ""
|
|
|
|
wrapMode: Text.WrapAnywhere
|
|
|
|
font.pixelSize: 18
|
2023-07-01 04:12:19 +08:00
|
|
|
}
|
2024-07-03 01:31:22 +08:00
|
|
|
}
|
|
|
|
RowLayout {
|
|
|
|
Layout.fillWidth: true
|
2023-07-01 04:12:19 +08:00
|
|
|
TextField {
|
2024-07-03 01:31:22 +08:00
|
|
|
id: usernameEdit
|
2023-07-01 04:12:19 +08:00
|
|
|
maximumLength: 32
|
|
|
|
Layout.fillWidth: true
|
2024-07-03 01:31:22 +08:00
|
|
|
placeholderText: "用户名"
|
|
|
|
text: selectedServer?.username ?? ""
|
2023-07-01 04:12:19 +08:00
|
|
|
}
|
|
|
|
TextField {
|
|
|
|
id: passwordEdit
|
2024-07-03 01:31:22 +08:00
|
|
|
maximumLength: 32
|
2023-07-01 04:12:19 +08:00
|
|
|
Layout.fillWidth: true
|
2024-07-03 01:31:22 +08:00
|
|
|
placeholderText: "密码"
|
2023-07-01 04:12:19 +08:00
|
|
|
passwordCharacter: "*"
|
2024-07-03 01:31:22 +08:00
|
|
|
echoMode: TextInput.Password
|
|
|
|
text: selectedServer?.password ?? ""
|
2023-07-01 04:12:19 +08:00
|
|
|
}
|
2024-07-03 01:31:22 +08:00
|
|
|
}
|
|
|
|
Button {
|
|
|
|
text: "登录(首次登录自动注册)"
|
|
|
|
Layout.fillWidth: true
|
|
|
|
enabled: !!(addressEdit.text && portEdit.text &&
|
|
|
|
usernameEdit.text && passwordEdit.text)
|
|
|
|
onClicked: {
|
|
|
|
const _addr = addressEdit.text;
|
|
|
|
const _port = parseInt(portEdit.text);
|
|
|
|
const _username = usernameEdit.text;
|
|
|
|
const _password = passwordEdit.text;
|
|
|
|
config.screenName = _username;
|
|
|
|
config.password = _password;
|
|
|
|
mainWindow.busy = true;
|
|
|
|
config.serverAddr = _addr;
|
|
|
|
config.serverPort = _port;
|
|
|
|
let name = selectedServer?.name;
|
|
|
|
if (_addr !== selectedServer?.addr || _port !== selectedServer?.port) {
|
|
|
|
name = "";
|
2023-07-01 04:12:19 +08:00
|
|
|
}
|
2024-07-03 01:31:22 +08:00
|
|
|
addFavorite(config.serverAddr, config.serverPort, name,
|
|
|
|
config.screenName, config.password);
|
|
|
|
Backend.joinServer(_addr, _port);
|
2023-07-01 04:12:19 +08:00
|
|
|
}
|
2024-07-03 01:31:22 +08:00
|
|
|
}
|
|
|
|
Button {
|
|
|
|
text: "从收藏夹删除"
|
|
|
|
Layout.fillWidth: true
|
|
|
|
visible: !!(selectedServer?.favorite)
|
|
|
|
onClicked: {
|
|
|
|
removeFavorite(selectedServer.addr, selectedServer.port);
|
2023-07-01 04:12:19 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-03 01:31:22 +08:00
|
|
|
GridView {
|
|
|
|
id: serverList
|
|
|
|
height: parent.height - 16 - serverListBar.height
|
|
|
|
width: parent.width - 24 - serverPanel.width
|
|
|
|
anchors.top: serverListBar.bottom
|
|
|
|
anchors.left: parent.left
|
|
|
|
anchors.margins: 8
|
|
|
|
model: ListModel { id: serverModel }
|
|
|
|
delegate: serverDelegate
|
|
|
|
cellHeight: 64 + 8
|
|
|
|
cellWidth: serverList.width / 2
|
2023-07-01 04:12:19 +08:00
|
|
|
clip: true
|
2024-07-03 01:31:22 +08:00
|
|
|
highlight: Rectangle {
|
|
|
|
color: "#AA9ABFEF"; radius: 5
|
|
|
|
// border.color: "black"; border.width: 2
|
2023-07-01 04:12:19 +08:00
|
|
|
}
|
2024-07-03 01:31:22 +08:00
|
|
|
currentIndex: -1
|
2023-07-01 04:12:19 +08:00
|
|
|
}
|
|
|
|
|
2024-07-03 01:31:22 +08:00
|
|
|
function addFavorite(addr, port, name, username, password) {
|
|
|
|
const newItem = config.addFavorite(addr, port, name, username, password);
|
|
|
|
if (!newItem) {
|
|
|
|
for (let i = 0; i < serverModel.count; i++) {
|
|
|
|
const s = serverModel.get(i);
|
|
|
|
if (s.addr === addr && s.port === port && s.favorite) {
|
|
|
|
s.name = name;
|
|
|
|
s.username = username;
|
|
|
|
s.password = password;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2023-07-01 04:12:19 +08:00
|
|
|
}
|
2024-07-03 01:31:22 +08:00
|
|
|
serverModel.insert(0, {
|
|
|
|
addr, port, name, username, password,
|
2023-10-03 00:19:12 +08:00
|
|
|
misMatchMsg: "",
|
2023-07-01 04:12:19 +08:00
|
|
|
description: qsTr("Server not up"),
|
2024-07-03 01:31:22 +08:00
|
|
|
online: "?",
|
|
|
|
capacity: "??",
|
|
|
|
favicon: "",
|
|
|
|
delayBegin: (new Date).getTime(),
|
|
|
|
delay: -1,
|
|
|
|
favorite: true,
|
|
|
|
lan: false,
|
2023-07-01 04:12:19 +08:00
|
|
|
});
|
2024-07-03 01:31:22 +08:00
|
|
|
Backend.getServerInfo(addr, port);
|
2023-07-01 04:12:19 +08:00
|
|
|
}
|
|
|
|
|
2024-07-03 01:31:22 +08:00
|
|
|
function removeFavorite(addr, port) {
|
|
|
|
config.removeFavorite(addr, port);
|
|
|
|
for (let i = 0; i < serverModel.count; i++) {
|
|
|
|
const s = serverModel.get(i);
|
|
|
|
if (s.addr === addr && s.port === port && s.favorite) {
|
|
|
|
serverModel.remove(i);
|
|
|
|
serverList.currentIndex = -1;
|
|
|
|
return;
|
|
|
|
}
|
2023-07-01 04:12:19 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-03 01:31:22 +08:00
|
|
|
function addLANServer(addr) {
|
|
|
|
const port = 9527;
|
|
|
|
if (config.findFavorite(addr, port)) return;
|
|
|
|
for (let i = 0; i < serverModel.count; i++) {
|
|
|
|
const s = serverModel.get(i);
|
|
|
|
if (s.addr === addr && s.port === port && s.lan) {
|
|
|
|
s.delayBegin = (new Date).getTime();
|
|
|
|
Backend.getServerInfo(addr, port);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!s.lan && !s.favorite) break;
|
2023-07-01 04:12:19 +08:00
|
|
|
}
|
2024-07-03 01:31:22 +08:00
|
|
|
serverModel.insert(0, {
|
|
|
|
addr, port,
|
|
|
|
name: "",
|
|
|
|
username: "",
|
|
|
|
password: "",
|
|
|
|
misMatchMsg: "",
|
|
|
|
description: qsTr("Server not up"),
|
|
|
|
online: "?",
|
|
|
|
capacity: "??",
|
|
|
|
favicon: "",
|
|
|
|
delayBegin: (new Date).getTime(),
|
|
|
|
delay: -1,
|
|
|
|
favorite: false,
|
|
|
|
lan: true,
|
|
|
|
});
|
|
|
|
Backend.getServerInfo(addr, port);
|
2023-07-01 04:12:19 +08:00
|
|
|
}
|
|
|
|
|
2024-07-03 01:31:22 +08:00
|
|
|
function updateServerDetail(addr, port, data) {
|
2023-07-01 04:12:19 +08:00
|
|
|
const [ver, icon, desc, capacity, count] = data;
|
|
|
|
for (let i = 0; i < serverModel.count; i++) {
|
|
|
|
const item = serverModel.get(i);
|
2024-07-03 01:31:22 +08:00
|
|
|
const ip = item.addr;
|
|
|
|
const itemPort = item.port;
|
|
|
|
if (addr === ip && port == itemPort) {
|
|
|
|
const ms = (new Date).getTime();
|
2024-01-25 03:23:29 +08:00
|
|
|
item.misMatchMsg = "";
|
|
|
|
if (FkVersion !== ver) {
|
|
|
|
item.misMatchMsg = qsTr("@VersionMismatch").arg(ver);
|
|
|
|
}
|
|
|
|
|
2024-07-03 01:31:22 +08:00
|
|
|
item.delay = ms - item.delayBegin;
|
2023-10-03 00:19:12 +08:00
|
|
|
item.description = desc;
|
2023-07-01 04:12:19 +08:00
|
|
|
item.favicon = icon;
|
|
|
|
item.online = count.toString();
|
|
|
|
item.capacity = capacity.toString();
|
2024-07-03 01:31:22 +08:00
|
|
|
return;
|
2023-07-01 04:12:19 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function loadConfig() {
|
2024-07-03 01:31:22 +08:00
|
|
|
if (serverModel.count > 0) { return; }
|
|
|
|
const serverList = JSON.parse(Backend.getPublicServerList());
|
|
|
|
serverList.unshift(...config.favoriteServers);
|
|
|
|
for (const server of serverList) {
|
|
|
|
let { addr, port, name, username, password } = server;
|
|
|
|
name = name ?? "";
|
|
|
|
username = username ?? "";
|
|
|
|
password = password ?? "";
|
|
|
|
if (port === -1) break;
|
|
|
|
if (!password && config.findFavorite(addr, port)) continue;
|
2023-07-01 04:12:19 +08:00
|
|
|
serverModel.append({
|
2024-07-03 01:31:22 +08:00
|
|
|
addr, port, name, username, password,
|
2023-10-03 00:19:12 +08:00
|
|
|
misMatchMsg: "",
|
2023-07-01 04:12:19 +08:00
|
|
|
description: qsTr("Server not up"),
|
2024-07-03 01:31:22 +08:00
|
|
|
online: "?",
|
|
|
|
capacity: "??",
|
2023-07-01 23:14:30 +08:00
|
|
|
favicon: "",
|
2024-07-03 01:31:22 +08:00
|
|
|
delayBegin: (new Date).getTime(),
|
|
|
|
delay: -1,
|
|
|
|
favorite: !!password,
|
|
|
|
lan: false,
|
2023-07-01 04:12:19 +08:00
|
|
|
});
|
2024-07-03 01:31:22 +08:00
|
|
|
Backend.getServerInfo(addr, port);
|
2023-07-01 04:12:19 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|