1
Fork 0
mirror of https://github.com/redstrate/Astra.git synced 2025-04-22 20:47:45 +00:00
astra/launcher/ui/Pages/LoginPage.qml
Joshua Goins 49f8aae877 Add support for installing the official benchmark
This uses the same profile system as the regular game, and can be used
to download the current benchmark (currently hardcoded, to be fixed
later.) Or as always, install it offline from an existing zip.
2024-04-19 20:32:28 -04:00

348 lines
No EOL
12 KiB
QML

// SPDX-FileCopyrightText: 2023 Joshua Goins <josh@redstrate.com>
// SPDX-License-Identifier: GPL-3.0-or-later
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls as QQC2
import QtQuick.Layouts
import org.kde.kirigami as Kirigami
import org.kde.kirigamiaddons.formcard as FormCard
import org.kde.kirigamiaddons.components as Components
import zone.xiv.astra
QQC2.Control {
id: page
readonly property string invalidLoginReason: {
if (!LauncherCore.currentProfile.account) {
return i18n("Profile has no associated account.");
}
if (usernameField.text.length === 0) {
return i18n("Username is required.");
}
if (LauncherCore.currentProfile.account.needsPassword && passwordField.text.length === 0) {
return i18n("Password is required.");
}
if (LauncherCore.currentProfile.account.useOTP && !LauncherCore.currentProfile.account.rememberOTP && otpField.text.length === 0) {
return i18n("OTP is required.");
}
if (LauncherCore.currentProfile.loggedIn) {
return i18n("Already logged in.");
}
return "";
}
readonly property bool isLoginValid: {
if (!LauncherCore.currentProfile.account) {
return false;
}
if (usernameField.text.length === 0) {
return false;
}
if (LauncherCore.currentProfile.account.needsPassword && passwordField.text.length === 0) {
return false;
}
if (LauncherCore.currentProfile.account.useOTP && !LauncherCore.currentProfile.account.rememberOTP && otpField.text.length === 0) {
return false;
}
if (LauncherCore.currentProfile.loggedIn) {
return false;
}
return true;
}
function updateFields() {
usernameField.text = LauncherCore.currentProfile.account.name;
passwordField.text = !LauncherCore.currentProfile.account.needsPassword && LauncherCore.currentProfile.account.rememberPassword ? LauncherCore.currentProfile.account.getPassword() : "";
otpField.text = "";
}
Connections {
target: LauncherCore
function onCurrentProfileChanged() {
page.updateFields();
LauncherCore.refreshLogoImage();
}
}
Connections {
target: LauncherCore.currentProfile
function onAccountChanged() {
page.updateFields();
if (LauncherCore.currentProfile.account.needsPassword) {
passwordField.forceActiveFocus();
return;
}
if (LauncherCore.currentProfile.account.useOTP) {
otpField.forceActiveFocus();
return;
}
loginButton.forceActiveFocus();
}
}
contentItem: ColumnLayout {
width: parent.width
spacing: Kirigami.Units.largeSpacing
Image {
readonly property real aspectRatio: sourceSize.height / sourceSize.width
fillMode: Image.PreserveAspectFit
source: "file://" + LauncherCore.cachedLogoImage
verticalAlignment: Image.AlignTop
sourceClipRect: Qt.rect(0, sourceSize.height / 2, sourceSize.width, sourceSize.height / 2)
Component.onCompleted: LauncherCore.refreshLogoImage()
Layout.preferredWidth: parent.width
Layout.preferredHeight: width * aspectRatio
}
FormCard.FormCard {
maximumWidth: Kirigami.Units.gridUnit * 25
visible: LauncherCore.profileManager.numProfiles > 1
Layout.fillWidth: true
FormCard.FormButtonDelegate {
id: currentProfileDelegate
text: LauncherCore.currentProfile.name
QQC2.Menu {
id: profileMenu
modal: true
Repeater {
model: LauncherCore.profileManager
QQC2.MenuItem {
id: profileMenuItem
required property var profile
QQC2.MenuItem {
text: profileMenuItem.profile.name
onClicked: {
LauncherCore.currentProfile = profileMenuItem.profile;
profileMenu.close();
}
}
}
}
}
onClicked: profileMenu.popup(currentProfileDelegate, currentProfileDelegate.width - profileMenu.width, currentProfileDelegate.height)
}
}
FormCard.FormCard {
id: regularLoginCard
visible: !LauncherCore.currentProfile.isBenchmark
maximumWidth: Kirigami.Units.gridUnit * 25
Layout.fillWidth: true
FormCard.FormButtonDelegate {
id: currentAccountDelegate
enabled: LauncherCore.accountManager.numAccounts > 1
text: LauncherCore.currentProfile.account.name
leading: Components.Avatar {
implicitWidth: Kirigami.Units.iconSizes.medium
implicitHeight: Kirigami.Units.iconSizes.medium
name: LauncherCore.currentProfile.account.name
source: LauncherCore.currentProfile.account.avatarUrl
}
leadingPadding: Kirigami.Units.largeSpacing * 2
QQC2.Menu {
id: accountMenu
modal: true
Repeater {
model: LauncherCore.accountManager
QQC2.MenuItem {
id: menuItem
required property var account
QQC2.MenuItem {
text: menuItem.account.name
icon.name: menuItem.account.avatarUrl.length === 0 ? "actor" : ""
icon.source: menuItem.account.avatarUrl
onClicked: {
LauncherCore.currentProfile.account = menuItem.account;
accountMenu.close();
}
}
}
}
}
onClicked: accountMenu.popup(currentAccountDelegate, currentAccountDelegate.width - accountMenu.width, currentAccountDelegate.height)
}
FormCard.FormDelegateSeparator {
above: currentAccountDelegate
below: usernameField
}
FormCard.FormTextFieldDelegate {
id: usernameField
label: LauncherCore.currentProfile.account.isSapphire ? i18n("Username") : i18n("Square Enix ID")
text: LauncherCore.currentProfile.account.name
enabled: false
QQC2.ToolTip.text: i18n("The username can only be changed under account settings.")
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
QQC2.ToolTip.visible: hovered
}
FormCard.FormDelegateSeparator {
above: usernameField
below: passwordField
}
FormCard.FormTextFieldDelegate {
id: passwordField
label: LauncherCore.currentProfile.account.isSapphire ? i18n("Password") : i18n("Square Enix Password")
echoMode: TextInput.Password
enabled: LauncherCore.currentProfile.account.rememberPassword ? LauncherCore.currentProfile.account.needsPassword : true
focus: true
onAccepted: {
if (otpField.visible) {
otpField.clicked();
} else {
loginButton.clicked();
}
}
text: (!LauncherCore.currentProfile.account.needsPassword && LauncherCore.currentProfile.account.rememberPassword) ? LauncherCore.currentProfile.account.getPassword() : ""
}
FormCard.FormDelegateSeparator {
above: passwordField
below: LauncherCore.currentProfile.account.useOTP ? otpField : loginButton
}
FormCard.FormTextFieldDelegate {
id: otpField
label: i18n("One-time Password")
visible: LauncherCore.currentProfile.account.useOTP
onAccepted: {
if (page.isLoginValid) {
loginButton.clicked()
}
}
}
FormCard.FormDelegateSeparator {
above: LauncherCore.currentProfile.account.useOTP ? otpField : passwordField
below: loginButton
visible: LauncherCore.currentProfile.account.useOTP
}
FormCard.FormButtonDelegate {
id: loginButton
text: i18n("Log In")
description: page.invalidLoginReason
icon.name: "unlock"
enabled: page.isLoginValid
onClicked: {
LauncherCore.login(LauncherCore.currentProfile, usernameField.text, passwordField.text, otpField.text)
page.Window.window.pageStack.layers.push(Qt.createComponent("zone.xiv.astra", "StatusPage"))
}
}
FormCard.FormDelegateSeparator {
above: loginButton
below: forgotPasswordButton
visible: !LauncherCore.currentProfile.account.isSapphire
}
FormCard.FormButtonDelegate {
id: forgotPasswordButton
text: i18n("Forgot ID or Password")
icon.name: "dialog-password"
visible: !LauncherCore.currentProfile.account.isSapphire
onClicked: applicationWindow().openUrl('https://secure.square-enix.com/account/app/svc/reminder')
}
}
FormCard.FormCard {
id: benchmarkLaunchCard
visible: LauncherCore.currentProfile.isBenchmark
maximumWidth: Kirigami.Units.gridUnit * 25
Layout.fillWidth: true
FormCard.FormButtonDelegate {
id: launchBenchmarkDelegate
text: i18n("Launch Benchmark")
onClicked: {
LauncherCore.login(LauncherCore.currentProfile, "", "", "")
page.Window.window.pageStack.layers.push(Qt.createComponent("zone.xiv.astra", "StatusPage"))
}
}
}
Item {
Layout.fillHeight: true
}
FormCard.FormCard {
maximumWidth: Kirigami.Units.gridUnit * 25
Layout.alignment: Qt.AlignBottom
FormCard.FormButtonDelegate {
text: i18nc("@action:button", "The Lodestone")
icon.name: "internet-services-symbolic"
visible: !LauncherCore.currentProfile.account.isSapphire
// TODO: how do we link to a "worldwide" lodestone, if that even exists?
onClicked: applicationWindow().openUrl('https://na.finalfantasyxiv.com/lodestone/')
}
FormCard.FormDelegateSeparator {}
FormCard.FormButtonDelegate {
text: i18nc("@action:button", "Mog Station")
icon.name: "internet-services-symbolic"
visible: !LauncherCore.currentProfile.account.isSapphire
onClicked: applicationWindow().openUrl('https://secure.square-enix.com/account/app/svc/mogstation/')
}
}
}
}