license login feature

This commit is contained in:
2026-09-01 22:25:23 +03:00
parent c25e071b29
commit d6986057d1
11 changed files with 1062 additions and 19 deletions
+101 -10
View File
@@ -31,6 +31,13 @@ Window {
: qsTr("Игра закрыта"),
crashed || exitCode !== 0 ? "#cc3333" : "#555555")
}
onMicrosoftLoginUrlReady: (url) => window.openMicrosoftLogin(url)
// Выбор в списке здесь не трогаем: новый профиль уже выбран тем, кто
// его создал, а повторный вход мог быть и не в последний профиль.
onMicrosoftLoginSucceeded: (playerName) =>
window.showToast(qsTr("Вход выполнен: %1").arg(playerName), "#4b7a1f")
onMicrosoftLoginFailed: (message) => window.showToast(message, "#cc3333", 8000)
onMicrosoftReloginRequired: (profileIndex) => backend.startMicrosoftLogin(profileIndex)
onGameOutput: (line) => console.log(line)
onSeasonalInstallFinished: (seasonalId, buildName) => {
window.showToast(qsTr("Сборка «%1» установлена — можно запускать").arg(buildName),
@@ -52,6 +59,27 @@ Window {
}
}
// Окно входа Microsoft создаётся по требованию, а не вместе с главным
// окном: MicrosoftLoginDialog.qml попадает в модуль только в сборках с Qt
// WebEngine, и обычная декларация сломала бы всё окно в остальных.
property var microsoftLoginDialog: null
function openMicrosoftLogin(url) {
if (microsoftLoginDialog === null) {
const component = Qt.createComponent("MicrosoftLoginDialog.qml")
if (component.status !== Component.Ready) {
backend.cancelMicrosoftLogin()
window.showToast(qsTr("Окно входа Microsoft недоступно: сборка без Qt WebEngine"),
"#cc3333", 8000)
return
}
microsoftLoginDialog = component.createObject(window, { backend: backend })
microsoftLoginDialog.failed.connect(
(message) => window.showToast(message, "#cc3333", 6000))
}
microsoftLoginDialog.openAt(url)
}
function formatMb(bytes) {
return (bytes / 1048576).toFixed(1)
}
@@ -557,7 +585,8 @@ Window {
id: pfLogin
x: 20
width: parent.width - 40
placeholderText: "Логин"
enabled: pfAuth.currentIndex !== 2
placeholderText: pfAuth.currentIndex === 2 ? "Ник придёт из аккаунта" : "Логин"
color: "#ffffff"
placeholderTextColor: "#666666"
background: Rectangle {
@@ -573,7 +602,7 @@ Window {
x: 20
width: parent.width - 40
enabled: pfAuth.currentIndex === 1
placeholderText: pfAuth.currentIndex === 1 ? "Пароль Ely.by" : "Не нужен в офлайне"
placeholderText: pfAuth.currentIndex === 1 ? "Пароль Ely.by" : "Не нужен для этого типа"
echoMode: TextInput.Password
color: "#ffffff"
placeholderTextColor: "#666666"
@@ -589,7 +618,9 @@ Window {
id: pfAuth
x: 20
width: parent.width - 40
model: ["Офлайн (без пароля)", "Ely.by"]
model: backend.microsoftAvailable
? ["Офлайн (без пароля)", "Ely.by", "Microsoft (лицензия)"]
: ["Офлайн (без пароля)", "Ely.by"]
}
}
@@ -641,10 +672,14 @@ Window {
onAccepted: {
const name = pfName.text.trim()
const type = pfAuth.currentIndex === 2 ? "microsoft"
: pfAuth.currentIndex === 1 ? "elyby" : "offline"
if (name !== "") {
backend.addProfile(name, pfLogin.text.trim(), pfPassword.text,
pfAuth.currentIndex === 1 ? "elyby" : "offline")
backend.addProfile(name, pfLogin.text.trim(), pfPassword.text, type)
profileBox.currentIndex = backend.profileNames.length - 1
// Профиль Microsoft без входа бесполезен: сразу показываем окно.
if (type === "microsoft")
backend.startMicrosoftLogin(backend.profileNames.length - 1)
}
pfName.text = ""; pfLogin.text = ""; pfPassword.text = ""; pfAuth.currentIndex = 0
}
@@ -665,6 +700,10 @@ Window {
padding: 0
property int editIndex: -1
// Состояние входа в Microsoft у открытого профиля — для строки статуса.
property bool msProfile: false
property bool msLinked: false
property string msName: ""
function openFor(index) {
const data = backend.profileAt(index)
@@ -672,7 +711,10 @@ Window {
epName.text = data.name || ""
epLogin.text = data.login || ""
epPassword.text = data.password || ""
epAuth.currentIndex = data.authType === "elyby" ? 1 : 0
msProfile = data.authType === "microsoft"
epAuth.currentIndex = msProfile ? 2 : data.authType === "elyby" ? 1 : 0
msLinked = data.hasMicrosoftSession === true
msName = data.resolvedName || ""
profileBox.popup.close()
open()
}
@@ -725,7 +767,8 @@ Window {
id: epLogin
x: 20
width: parent.width - 40
placeholderText: "Логин"
enabled: epAuth.currentIndex !== 2
placeholderText: epAuth.currentIndex === 2 ? "Ник придёт из аккаунта" : "Логин"
color: "#ffffff"
placeholderTextColor: "#666666"
background: Rectangle {
@@ -741,7 +784,7 @@ Window {
x: 20
width: parent.width - 40
enabled: epAuth.currentIndex === 1
placeholderText: epAuth.currentIndex === 1 ? "Пароль Ely.by" : "Не нужен в офлайне"
placeholderText: epAuth.currentIndex === 1 ? "Пароль Ely.by" : "Не нужен для этого типа"
echoMode: TextInput.Password
color: "#ffffff"
placeholderTextColor: "#666666"
@@ -757,7 +800,54 @@ Window {
id: epAuth
x: 20
width: parent.width - 40
model: ["Офлайн (без пароля)", "Ely.by"]
// Тип уже сохранённого профиля показываем всегда: иначе в
// сборке без WebEngine он молча стал бы офлайновым.
model: (backend.microsoftAvailable || editProfileDialog.msProfile)
? ["Офлайн (без пароля)", "Ely.by", "Microsoft (лицензия)"]
: ["Офлайн (без пароля)", "Ely.by"]
}
// Состояние аккаунта Microsoft и кнопка повторного входа: токен
// может протухнуть, а сменить аккаунт иначе нечем.
Column {
x: 20
width: parent.width - 40
spacing: 8
visible: epAuth.currentIndex === 2
Text {
text: editProfileDialog.msLinked
? qsTr("Вход выполнен: %1").arg(editProfileDialog.msName)
: qsTr("Вход не выполнен")
color: editProfileDialog.msLinked ? "#91B315" : "#aaaaaa"
font.pixelSize: 13
}
Button {
width: parent.width; height: 34
enabled: backend.microsoftAvailable
text: editProfileDialog.msLinked ? "Войти заново" : "Войти в Microsoft"
contentItem: Text {
text: parent.text
color: "#ffffff"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
background: Rectangle {
color: parent.pressed ? "#6a8510" : "#91B315"
radius: 6
}
onClicked: {
// Тип профиля мог быть только что переключён на
// Microsoft — сохраняем его до входа, иначе backend
// припишет токены профилю другого типа.
backend.updateProfile(editProfileDialog.editIndex,
epName.text.trim(), epLogin.text.trim(),
epPassword.text, "microsoft")
editProfileDialog.close()
backend.startMicrosoftLogin(editProfileDialog.editIndex)
}
}
}
}
@@ -811,7 +901,8 @@ Window {
const name = epName.text.trim()
if (editIndex >= 0 && name !== "")
backend.updateProfile(editIndex, name, epLogin.text.trim(), epPassword.text,
epAuth.currentIndex === 1 ? "elyby" : "offline")
epAuth.currentIndex === 2 ? "microsoft"
: epAuth.currentIndex === 1 ? "elyby" : "offline")
editIndex = -1
epName.text = ""; epLogin.text = ""; epPassword.text = ""
}