FreeKill/qml/main.qml
notify fc8be0ad40
神貂蝉 (#138)
控制他人/一控多相关
2023-04-27 14:15:08 +08:00

259 lines
6.1 KiB
QML

// SPDX-License-Identifier: GPL-3.0-or-later
import QtQuick
import QtQuick.Controls
import QtQuick.Window
import "Logic.js" as Logic
import "Pages"
Window {
id: realMainWin
visible: true
width: 960
height: 540
minimumWidth: 160
minimumHeight: 90
title: "FreeKill v" + FkVersion
property var callbacks: Logic.callbacks
Item {
id: mainWindow
width: (parent.width / parent.height < 960 / 540)
? 960 : 540 * parent.width / parent.height
height: (parent.width / parent.height > 960 / 540)
? 540 : 960 * parent.height / parent.width
scale: parent.width / width
anchors.centerIn: parent
property bool is_pending: false
property var pending_message: []
Config {
id: config
}
Image {
source: config.lobbyBg
anchors.fill: parent
fillMode: Image.PreserveAspectCrop
}
FontLoader { id: fontLibian; source: AppPath + "/fonts/FZLBGBK.ttf" }
FontLoader { id: fontLi2; source: AppPath + "/fonts/FZLE.ttf" }
StackView {
id: mainStack
visible: !mainWindow.busy
// If error occurs during loading initialItem, the program will fall into "polish()" loop
// initialItem: OS !== "Web" ? init : webinit
anchors.fill: parent
}
Component { id: init; Init {} }
Component { id: webinit; WebInit {} }
Component { id: packageManage; PackageManage {} }
Component { id: lobby; Lobby {} }
Component { id: generalsOverview; GeneralsOverview {} }
Component { id: cardsOverview; CardsOverview {} }
Component { id: modesOverview; ModesOverview {} }
Component { id: room; Room {} }
Component { id: aboutPage; About {} }
property var generalsOverviewPage
property var cardsOverviewPage
property alias modesOverviewPage: modesOverview
property alias aboutPage: aboutPage
property bool busy: false
property string busyText: ""
onBusyChanged: busyText = "";
BusyIndicator {
running: true
anchors.centerIn: parent
visible: mainWindow.busy === true
}
Item {
visible: mainWindow.busy === true && mainWindow.busyText !== ""
anchors.bottom: parent.bottom
height: 32
width: parent.width
Rectangle {
anchors.fill: parent
color: "#88EEEEEE"
}
Text {
anchors.centerIn: parent
text: mainWindow.busyText
font.pixelSize: 24
}
}
// global popup. it is modal and just lower than toast
Rectangle {
id: globalPopupDim
anchors.fill: parent
color: "black"
opacity: 0
visible: !mainWindow.busy
property bool stateVisible: false
states: [
State {
when: globalPopupDim.stateVisible
PropertyChanges { target: globalPopupDim; opacity: 0.5 }
},
State {
when: !globalPopupDim.stateVisible
PropertyChanges { target: globalPopupDim; opacity: 0.0 }
}
]
transitions: Transition {
NumberAnimation { properties: "opacity"; easing.type: Easing.InOutQuad }
}
}
Popup {
id: globalPopup
property string source: ""
modal: true
dim: false // cannot animate the dim
focus: true
opacity: mainWindow.busy ? 0 : 1
closePolicy: Popup.CloseOnEscape
anchors.centerIn: parent
onAboutToShow: {
globalPopupDim.stateVisible = true
}
enter: Transition {
NumberAnimation { properties: "opacity"; from: 0; to: 1 }
NumberAnimation { properties: "scale"; from: 0.4; to: 1 }
}
onAboutToHide: {
globalPopupDim.stateVisible = false
}
exit: Transition {
NumberAnimation { properties: "opacity"; from: 1; to: 0 }
NumberAnimation { properties: "scale"; from: 1; to: 0.4 }
}
Loader {
visible: !mainWindow.busy
source: globalPopup.source === "" ? "" : "GlobalPopups/" + globalPopup.source
onSourceChanged: {
if (item === null)
return;
item.finished.connect(() => {
globalPopup.close();
globalPopup.source = "";
});
}
}
}
Popup {
id: errDialog
property string txt: ""
modal: true
anchors.centerIn: parent
width: Math.min(contentWidth + 24, realMainWin.width * 0.9)
height: Math.min(contentHeight + 24, realMainWin.height * 0.9)
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
padding: 12
contentItem: Text {
text: errDialog.txt
wrapMode: Text.WordWrap
TapHandler {
onTapped: errDialog.close();
}
}
}
ToastManager {
id: toast
}
Connections {
target: Backend
function onNotifyUI(command, jsonData) {
if (command === "ErrorDialog") {
errDialog.txt = jsonData;
errDialog.open();
return;
}
if (mainWindow.is_pending && command !== "ChangeSelf") {
mainWindow.pending_message.push({ command: command, jsonData: jsonData });
} else {
if (command === "StartChangeSelf") {
mainWindow.is_pending = true;
}
mainWindow.handleMessage(command, jsonData);
}
}
}
function fetchMessage() {
let ret = pending_message.splice(0, 1)[0];
if (pending_message.length === 0) {
is_pending = false;
}
return ret;
}
function handleMessage(command, jsonData) {
let cb = callbacks[command]
if (typeof(cb) === "function") {
cb(jsonData);
} else {
callbacks["ErrorMsg"]("Unknown command " + command + "!");
}
}
}
Shortcut {
sequences: [ StandardKey.FullScreen ]
onActivated: {
if (realMainWin.visibility === Window.FullScreen)
realMainWin.showNormal();
else
realMainWin.showFullScreen();
}
}
Loader {
id: splashLoader
anchors.fill: parent
}
Component.onCompleted: {
if (OS !== "Web") {
mainStack.push(init);
if (!Debugging) {
splashLoader.source = "Splash.qml";
splashLoader.item.disappeared.connect(() => {
splashLoader.source = "";
});
}
} else {
mainStack.push(webinit);
}
if (OS !== "Android" && OS !== "Web") {
x = config.winX;
y = config.winY;
width = config.winWidth;
height = config.winHeight;
}
}
onClosing: {
config.winWidth = width;
config.winHeight = height;
config.saveConf();
Backend.quitLobby();
}
}