// SPDX-License-Identifier: GPL-3.0-or-later
import QtQuick
import QtQuick.Controls
import QtQuick.Window
import QtQuick.Layouts
import Fk.LobbyElement
import Fk.Common
import "Logic.js" as Logic
Item {
id: root
property alias roomModel: roomModel
property var roomInfoCache: ({})
property string password
Component {
id: roomDelegate
Rectangle {
radius: 8
height: 124 - 8
width: 124 - 8
color: outdated ? "#E2E2E2" : "#DDDDDDDD"
Text {
id: roomNameText
horizontalAlignment: Text.AlignLeft
width: parent.width - 16
height: contentHeight
maximumLineCount: 2
wrapMode: Text.WrapAnywhere
textFormat: Text.PlainText
text: roomName
// color: outdated ? "gray" : "black"
font.pixelSize: 16
font.strikeout: outdated
// elide: Label.ElideRight
anchors.top: parent.top
anchors.left: parent.left
anchors.margins: 8
}
Text {
id: roomIdText
text: luatr(gameMode) + ' #' + roomId
font.strikeout: outdated
anchors.top: roomNameText.bottom
anchors.left: roomNameText.left
}
Image {
source: AppPath + "/image/button/skill/locked.png"
visible: hasPassword
scale: 0.8
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.margins: -4
}
Text {
color: (playerNum == capacity) ? "red" : "black"
text: playerNum + "/" + capacity
font.pixelSize: 18
font.bold: true
anchors.bottom: parent.bottom
anchors.bottomMargin: 8
anchors.right: parent.right
anchors.rightMargin: 8
}
TapHandler {
gesturePolicy: TapHandler.WithinBounds
enabled: !opTimer.running && !outdated
onTapped: {
lobby_dialog.sourceComponent = roomDetailDialog;
lobby_dialog.item.roomData = {
roomId, roomName, gameMode, playerNum, capacity,
hasPassword, outdated,
};
lobby_dialog.item.roomConfig = config.roomConfigCache?.[config.serverAddr]?.[roomId]
lobby_drawer.open();
}
}
}
}
Component {
id: roomDetailDialog
ColumnLayout {
property var roomData: ({
roomName: "",
hasPassword: true,
})
property var roomConfig: undefined
signal finished()
anchors.fill: parent
anchors.margins: 16
Text {
text: roomData.roomName
font.pixelSize: 18
}
Text {
font.pixelSize: 18
text: {
let ret = luatr(roomData.gameMode);
ret += (' #' + roomData.roomId);
ret += (' ' + roomData.playerNum + '/' + roomData.capacity);
return ret;
}
}
Item { Layout.fillHeight: true }
// Dummy
Text {
text: "在未来的版本中这一块区域将增加更多实用的功能,
"+
"例如直接查看房间的各种配置信息
"+
"以及更多与禁将有关的实用功能!"+
"注:灰色按钮为试做型UI 后面优化"
font.pixelSize: 18
}
RowLayout {
Layout.fillWidth: true
Text {
visible: roomData.hasPassword
text: luatr("Please input room's password")
}
TextField {
id: passwordEdit
visible: roomData.hasPassword
Layout.fillWidth: true
onTextChanged: root.password = text;
}
Item {
visible: !roomData.hasPassword
Layout.fillWidth: true
}
Button {
// text: "OK"
text: (roomData.playerNum < roomData.capacity) ? luatr("Enter") : luatr("Observe")
onClicked: {
enterRoom(roomData.roomId, roomData.playerNum, roomData.capacity,
roomData.hasPassword ? root.password : "");
lobby_dialog.item.finished();
}
}
}
Component.onCompleted: {
passwordEdit.text = "";
}
}
}
ListModel {
id: roomModel
}
PersonalSettings {}
Timer {
id: opTimer
interval: 1000
}
ColumnLayout {
id: roomListLayout
height: root.height - 72
y: 16
anchors.left: parent.left
anchors.leftMargin: root.width * 0.03 + root.width * 0.94 * 0.8 % 128 / 2
width: {
let ret = root.width * 0.94 * 0.8;
ret -= ret % 128;
return ret;
}
clip: true
RowLayout {
Layout.fillWidth: true
Item { Layout.fillWidth: true }
Button {
Layout.alignment: Qt.AlignRight
text: luatr("Refresh Room List").arg(roomModel.count)
enabled: !opTimer.running
onClicked: {
opTimer.start();
ClientInstance.notifyServer("RefreshRoomList", "");
}
}
Button {
text: luatr("Filter")
onClicked: {
lobby_dialog.sourceComponent = Qt.createComponent("../LobbyElement/FilterRoom.qml"); //roomFilterDialog;
lobby_drawer.open();
}
}
Button {
text: luatr("Create Room")
onClicked: {
lobby_dialog.sourceComponent =
Qt.createComponent("../LobbyElement/CreateRoom.qml");
lobby_drawer.open();
config.observing = false;
config.replaying = false;
}
}
}
GridView {
id: roomList
cellWidth: 128
cellHeight: 128
Layout.fillHeight: true
Layout.fillWidth: true
ScrollBar.vertical: ScrollBar {}
delegate: roomDelegate
clip: true
model: roomModel
}
}
Rectangle {
id: serverInfoLayout
height: root.height - 112
y: 56
width: root.width * 0.94 * 0.2
anchors.right: parent.right
anchors.rightMargin: root.width * 0.03
// anchors.horizontalCenter: parent.horizontalCenter
color: "#88EEEEEE"
property bool chatShown: true
Flickable {
ScrollBar.vertical: ScrollBar {}
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
anchors.topMargin: 10
flickableDirection: Flickable.VerticalFlick
width: parent.width - 10
height: parent.height - 10 - (parent.chatShown ? 200 : 0)
contentHeight: bulletin_info.height
clip: true
Text {
id: bulletin_info
width: parent.width
wrapMode: TextEdit.WordWrap
textFormat: Text.MarkdownText
text: config.serverMotd + "\n\n___\n\n" + luatr('Bulletin Info')
onLinkActivated: Qt.openUrlExternally(link);
}
}
MetroButton {
text: "🗨️" + (parent.chatShown ? "➖" : "➕")
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: lobbyChat.top
onClicked: {
parent.chatShown = !parent.chatShown
}
}
ChatBox {
id: lobbyChat
width: parent.width
height: parent.chatShown ? 200 : 0
Behavior on height { NumberAnimation { duration: 200 } }
anchors.bottom: parent.bottom
isLobby: true
color: "#88EEEEEE"
clip: true
}
}
RowLayout {
id: buttonRow
anchors.left: parent.left
anchors.bottom: parent.bottom
width: parent.width
Rectangle {
Layout.fillHeight: true
Layout.preferredWidth: childrenRect.width + 72
gradient: Gradient {
orientation: Gradient.Horizontal
GradientStop { position: 0.8; color: "white" }
GradientStop { position: 1.0; color: "transparent" }
}
Text {
x: 16; y: 4
font.pixelSize: 16
text: luatr("$OnlineInfo")
.arg(lobbyPlayerNum).arg(serverPlayerNum) + "\n"
+ "Powered by FreeKill " + FkVersion
}
}
Item { Layout.fillWidth: true }
Button {
text: luatr("Generals Overview")
onClicked: {
mainStack.push(mainWindow.generalsOverviewPage);
mainStack.currentItem.loadPackages();
}
}
Button {
text: luatr("Cards Overview")
onClicked: {
mainStack.push(mainWindow.cardsOverviewPage);
mainStack.currentItem.loadPackages();
}
}
Button {
text: luatr("Modes Overview")
onClicked: {
mainStack.push(mainWindow.modesOverviewPage);
}
}
Button {
text: luatr("Replay")
onClicked: {
mainStack.push(mainWindow.replayPage);
}
}
Button {
text: luatr("About")
onClicked: {
mainStack.push(mainWindow.aboutPage);
}
}
}
Button {
id: exitButton
anchors.right: parent.right
text: luatr("Exit Lobby")
display: AbstractButton.TextBesideIcon
icon.name: "application-exit"
onClicked: {
toast.show("Goodbye.");
mainStack.pop();
config.saveConf();
Backend.quitLobby();
}
}
Popup {
id: lobby_drawer
width: realMainWin.width * 0.8
height: realMainWin.height * 0.8
anchors.centerIn: parent
background: Rectangle {
color: "#EEEEEEEE"
radius: 5
border.color: "#A6967A"
border.width: 1
}
Loader {
id: lobby_dialog
anchors.centerIn: parent
width: parent.width / mainWindow.scale
height: parent.height / mainWindow.scale
scale: mainWindow.scale
clip: true
onSourceChanged: {
if (item === null)
return;
item.finished.connect(() => {
sourceComponent = undefined;
lobby_drawer.close();
});
}
onSourceComponentChanged: sourceChanged();
}
}
function enterRoom(roomId, playerNum, capacity, pw) {
config.replaying = false;
if (playerNum < capacity) {
config.observing = false;
lcall("SetObserving", false);
mainWindow.busy = true;
ClientInstance.notifyServer(
"EnterRoom",
JSON.stringify([roomId, pw])
);
} else {
config.observing = true;
lcall("SetObserving", true);
mainWindow.busy = true;
ClientInstance.notifyServer(
"ObserveRoom",
JSON.stringify([roomId, pw])
);
}
}
property int lobbyPlayerNum: 0
property int serverPlayerNum: 0
/*
function updateOnlineInfo() {
}
onLobbyPlayerNumChanged: updateOnlineInfo();
onServerPlayerNumChanged: updateOnlineInfo();
/*
*/
Danmaku {
id: danmaku
width: parent.width
}
function addToChat(pid, raw, msg) {
if (raw.type !== 1) return;
msg = msg.replace(/\{emoji([0-9]+)\}/g,
'');
raw.msg = raw.msg.replace(/\{emoji([0-9]+)\}/g,
'');
lobbyChat.append(msg);
danmaku.sendLog("" + raw.userName + ": " + raw.msg);
}
function sendDanmaku(msg) {
danmaku.sendLog(msg);
lobbyChat.append(msg);
}
Component.onCompleted: {
toast.show(luatr("$WelcomeToLobby"));
}
}