diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt
index 947cba9..b698747 100644
--- a/launcher/CMakeLists.txt
+++ b/launcher/CMakeLists.txt
@@ -47,6 +47,7 @@ qt_target_qml_sources(astra
QML_FILES
ui/Components/FormFileDelegate.qml
ui/Components/FormFolderDelegate.qml
+ ui/Pages/AutoLoginPage.qml
ui/Pages/BrowserPage.qml
ui/Pages/LoginPage.qml
ui/Pages/MainPage.qml
diff --git a/launcher/config.kcfg b/launcher/config.kcfg
index 09969e3..7714bb5 100644
--- a/launcher/config.kcfg
+++ b/launcher/config.kcfg
@@ -32,5 +32,7 @@ SPDX-License-Identifier: CC0-1.0
square-enix.com
+
+
diff --git a/launcher/include/launchercore.h b/launcher/include/launchercore.h
index df565ef..bb023d2 100755
--- a/launcher/include/launchercore.h
+++ b/launcher/include/launchercore.h
@@ -74,6 +74,7 @@ class LauncherCore : public QObject
Q_PROPERTY(QString squareEnixLoginServer READ squareEnixLoginServer WRITE setSquareEnixLoginServer NOTIFY squareEnixLoginServerChanged)
Q_PROPERTY(Headline *headline READ headline NOTIFY newsChanged)
Q_PROPERTY(Profile *currentProfile READ currentProfile WRITE setCurrentProfile NOTIFY currentProfileChanged)
+ Q_PROPERTY(Profile *autoLoginProfile READ autoLoginProfile WRITE setAutoLoginProfile NOTIFY autoLoginProfileChanged)
public:
LauncherCore();
@@ -100,7 +101,7 @@ public:
* The launcher will still warn the user about any possible errors, however the call site will need to check the
* result to see whether they need to "reset" or show a failed state or not.
*/
- bool autoLogin(Profile &settings);
+ Q_INVOKABLE void autoLogin(Profile *profile);
/*
* Launches the game using the provided authentication.
@@ -139,6 +140,10 @@ public:
[[nodiscard]] QString squareEnixLoginServer() const;
void setSquareEnixLoginServer(const QString &value);
+ [[nodiscard]] QString autoLoginProfileName() const;
+ [[nodiscard]] Profile *autoLoginProfile() const;
+ void setAutoLoginProfile(Profile *value);
+
Q_INVOKABLE GameInstaller *createInstaller(Profile *profile);
Q_INVOKABLE CompatibilityToolInstaller *createCompatInstaller();
@@ -177,6 +182,7 @@ signals:
void stageDeterminate(int min, int max, int value);
void newsChanged();
void currentProfileChanged();
+ void autoLoginProfileChanged();
private:
QCoro::Task<> beginLogin(LoginInformation &info);
diff --git a/launcher/include/profilemanager.h b/launcher/include/profilemanager.h
index 1e83e67..787a167 100644
--- a/launcher/include/profilemanager.h
+++ b/launcher/include/profilemanager.h
@@ -30,6 +30,7 @@ public:
[[nodiscard]] QHash roleNames() const override;
Q_INVOKABLE Profile *getProfile(int index);
+ Profile *getProfileByUUID(const QString &uuid);
int getProfileIndex(const QString &name);
Q_INVOKABLE Profile *addProfile();
diff --git a/launcher/src/launchercore.cpp b/launcher/src/launchercore.cpp
index 93020f7..632a8d0 100755
--- a/launcher/src/launchercore.cpp
+++ b/launcher/src/launchercore.cpp
@@ -448,12 +448,9 @@ void LauncherCore::login(Profile *profile, const QString &username, const QStrin
beginLogin(*loginInformation);
}
-bool LauncherCore::autoLogin(Profile &profile)
+void LauncherCore::autoLogin(Profile *profile)
{
- // TODO: when login fails, we need some way to propagate this back? or not?
- login(&profile, profile.account()->name(), profile.account()->getPassword(), profile.account()->getOTP());
-
- return true;
+ login(profile, profile->account()->name(), profile->account()->getPassword(), profile->account()->useOTP() ? profile->account()->getOTP() : QString());
}
GameInstaller *LauncherCore::createInstaller(Profile *profile)
@@ -585,6 +582,36 @@ void LauncherCore::setSquareEnixLoginServer(const QString &value)
}
}
+[[nodiscard]] QString LauncherCore::autoLoginProfileName() const
+{
+ return Config::autoLoginProfile();
+}
+
+[[nodiscard]] Profile *LauncherCore::autoLoginProfile() const
+{
+ if (Config::autoLoginProfile().isEmpty()) {
+ return nullptr;
+ }
+ return m_profileManager->getProfileByUUID(Config::autoLoginProfile());
+}
+
+void LauncherCore::setAutoLoginProfile(Profile *profile)
+{
+ if (profile == nullptr) {
+ Config::setAutoLoginProfile({});
+ Config::self()->save();
+ Q_EMIT autoLoginProfileChanged();
+ return;
+ }
+
+ auto uuid = profile->uuid();
+ if (uuid != Config::autoLoginProfile()) {
+ Config::setAutoLoginProfile(uuid);
+ Config::self()->save();
+ Q_EMIT autoLoginProfileChanged();
+ }
+}
+
void LauncherCore::refreshNews()
{
fetchNews();
diff --git a/launcher/src/profilemanager.cpp b/launcher/src/profilemanager.cpp
index 0b338b6..b6be493 100644
--- a/launcher/src/profilemanager.cpp
+++ b/launcher/src/profilemanager.cpp
@@ -28,6 +28,16 @@ int ProfileManager::getProfileIndex(const QString &name)
return -1;
}
+Profile *ProfileManager::getProfileByUUID(const QString &uuid)
+{
+ for (auto &m_profile : m_profiles) {
+ if (m_profile->uuid() == uuid)
+ return m_profile;
+ }
+
+ return nullptr;
+}
+
Profile *ProfileManager::addProfile()
{
auto newProfile = new Profile(m_launcher, QUuid::createUuid().toString(), this);
@@ -91,6 +101,7 @@ void ProfileManager::load()
auto config = KSharedConfig::openStateConfig();
for (const auto &id : config->groupList()) {
if (id.contains(QLatin1String("profile-"))) {
+ qInfo() << "Adding profile" << id;
auto profile = new Profile(m_launcher, QString(id).remove(QLatin1String("profile-")), this);
insertProfile(profile);
}
diff --git a/launcher/src/squarelauncher.cpp b/launcher/src/squarelauncher.cpp
index b8c1102..564a47c 100644
--- a/launcher/src/squarelauncher.cpp
+++ b/launcher/src/squarelauncher.cpp
@@ -104,6 +104,8 @@ QCoro::Task<> SquareLauncher::login(const LoginInformation &info)
const auto [stored, referer] = *storedResult;
+ qInfo() << "Performing oauth...";
+
QUrlQuery postData;
postData.addQueryItem(QStringLiteral("_STORED_"), stored);
postData.addQueryItem(QStringLiteral("sqexid"), info.username);
diff --git a/launcher/ui/Main.qml b/launcher/ui/Main.qml
index db0a0e8..9ea2910 100644
--- a/launcher/ui/Main.qml
+++ b/launcher/ui/Main.qml
@@ -46,10 +46,19 @@ Kirigami.ApplicationWindow {
profile: LauncherCore.currentProfile
})
} else {
- pageStack.layers.replace(Qt.createComponent("zone.xiv.astra", "MainPage"))
+ if (LauncherCore.autoLoginProfile) {
+ pageStack.layers.replace(Qt.createComponent("zone.xiv.astra", "AutoLoginPage"))
+ } else {
+ pageStack.layers.replace(Qt.createComponent("zone.xiv.astra", "MainPage"))
+ }
}
}
+ function cancelAutoLogin() {
+ pageStack.layers.clear();
+ pageStack.layers.replace(Qt.createComponent("zone.xiv.astra", "MainPage"));
+ }
+
function pushDialogLayer(url) {
if (LauncherCore.isSteamDeck) {
pageStack.layers.push(url)
diff --git a/launcher/ui/Pages/AutoLoginPage.qml b/launcher/ui/Pages/AutoLoginPage.qml
new file mode 100644
index 0000000..942f592
--- /dev/null
+++ b/launcher/ui/Pages/AutoLoginPage.qml
@@ -0,0 +1,44 @@
+// SPDX-FileCopyrightText: 2023 Joshua Goins
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+import QtQuick
+import QtQuick.Controls as QQC2
+
+import org.kde.kirigami as Kirigami
+
+import zone.xiv.astra
+
+Kirigami.Page {
+ id: root
+
+ title: i18n("Auto Login")
+
+ Kirigami.LoadingPlaceholder {
+ id: placeholderMessage
+
+ anchors.centerIn: parent
+
+ text: i18n("Logging in...")
+
+ helpfulAction: Kirigami.Action {
+ icon.name: "Cancel"
+ text: "Cancel"
+ enabled: autoLoginTimer.running
+ onTriggered: {
+ autoLoginTimer.stop();
+ applicationWindow().cancelAutoLogin();
+ }
+ }
+ }
+
+ Timer {
+ id: autoLoginTimer
+
+ interval: 5000
+ running: true
+ onTriggered: {
+ LauncherCore.autoLogin(LauncherCore.autoLoginProfile);
+ pageStack.layers.push(Qt.createComponent("zone.xiv.astra", "StatusPage"));
+ }
+ }
+}
diff --git a/launcher/ui/Settings/GeneralSettings.qml b/launcher/ui/Settings/GeneralSettings.qml
index fd10104..92aa6a5 100644
--- a/launcher/ui/Settings/GeneralSettings.qml
+++ b/launcher/ui/Settings/GeneralSettings.qml
@@ -1,6 +1,9 @@
// SPDX-FileCopyrightText: 2023 Joshua Goins
// SPDX-License-Identifier: GPL-3.0-or-later
+import QtQuick
+import QtQuick.Controls as QQC2
+
import org.kde.kirigamiaddons.formcard as FormCard
import zone.xiv.astra
@@ -13,6 +16,43 @@ FormCard.FormCardPage {
}
FormCard.FormCard {
+ FormCard.FormButtonDelegate {
+ text: i18n("Auto-login Profile")
+ description: LauncherCore.autoLoginProfile ? LauncherCore.autoLoginProfile.name : i18n("Disabled")
+
+ QQC2.Menu {
+ id: profileMenu
+
+ QQC2.MenuItem {
+ text: "Disabled"
+
+ onClicked: {
+ LauncherCore.autoLoginProfile = null;
+ profileMenu.close();
+ }
+ }
+
+ Repeater {
+ model: LauncherCore.profileManager
+
+ QQC2.MenuItem {
+ required property var profile
+
+ text: profile.name
+
+ onClicked: {
+ LauncherCore.autoLoginProfile = profile;
+ profileMenu.close();
+ }
+ }
+ }
+ }
+
+ onClicked: profileMenu.popup()
+ }
+
+ FormCard.FormDelegateSeparator {}
+
FormCard.FormCheckDelegate {
id: closeAstraDelegate