1
Fork 0
mirror of https://github.com/redstrate/Astra.git synced 2025-06-07 22:47:46 +00:00

Use KConfig's own class instead of "proxying" it in Account

This will make it trivial to add more account settings in the future.
This commit is contained in:
Joshua Goins 2025-03-17 18:27:17 -04:00
parent 799b718818
commit da3084266c
12 changed files with 107 additions and 279 deletions

View file

@ -90,10 +90,10 @@ target_link_libraries(astra_static PUBLIC
QCoro::Core
QCoro::Network
QCoro::Qml)
kconfig_target_kcfg_file(astra_static FILE config.kcfg CLASS_NAME Config MUTATORS GENERATE_PROPERTIES GENERATE_MOC DEFAULT_VALUE_GETTERS PARENT_IN_CONSTRUCTOR QML_REGISTRATION QML_UNCREATABLE)
kconfig_target_kcfg_file(astra_static FILE accountconfig.kcfg CLASS_NAME AccountConfig MUTATORS GENERATE_PROPERTIES GENERATE_MOC DEFAULT_VALUE_GETTERS PARENT_IN_CONSTRUCTOR QML_REGISTRATION QML_UNCREATABLE)
kconfig_target_kcfg_file(astra_static FILE config.kcfg CLASS_NAME Config MUTATORS GENERATE_PROPERTIES GENERATE_MOC DEFAULT_VALUE_GETTERS PARENT_IN_CONSTRUCTOR QML_REGISTRATION QML_UNCREATABLE USE_ENUM_TYPES)
kconfig_target_kcfg_file(astra_static FILE accountconfig.kcfg CLASS_NAME AccountConfig MUTATORS GENERATE_PROPERTIES GENERATE_MOC DEFAULT_VALUE_GETTERS PARENT_IN_CONSTRUCTOR QML_REGISTRATION QML_UNCREATABLE USE_ENUM_TYPES)
kconfig_target_kcfg_file(astra_static FILE profileconfig.kcfg CLASS_NAME ProfileConfig MUTATORS GENERATE_PROPERTIES GENERATE_MOC DEFAULT_VALUE_GETTERS PARENT_IN_CONSTRUCTOR QML_REGISTRATION QML_UNCREATABLE)
target_include_directories(astra_static PUBLIC include ${CMAKE_BINARY_DIR})
target_include_directories(astra_static PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_BINARY_DIR})
if (NOT MSVC)
target_compile_options(astra_static PUBLIC -fexceptions)

View file

@ -11,6 +11,7 @@ SPDX-License-Identifier: CC0-1.0
<kcfgfile name="astrastaterc" stateConfig="true">
<parameter name="uuid"/>
</kcfgfile>
<include>account.h</include>
<group name="account-$(uuid)">
<entry key="Name" type="string">
</entry>
@ -50,7 +51,7 @@ SPDX-License-Identifier: CC0-1.0
<default>false</default>
</entry>
<entry name="License" type="Enum">
<choices>
<choices name="Account::GameLicense">
<choice name="WindowsStandalone">
</choice>
<choice name="WindowsSteam">

View file

@ -6,7 +6,7 @@
#include <QtQml>
#include <qcorotask.h>
#include "accountconfig.h"
class AccountConfig;
class Account : public QObject
{
@ -14,59 +14,24 @@ class Account : public QObject
QML_ELEMENT
QML_UNCREATABLE("Use from AccountManager")
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
Q_PROPERTY(int language READ language WRITE setLanguage NOTIFY languageChanged)
Q_PROPERTY(QString lodestoneId READ lodestoneId WRITE setLodestoneId NOTIFY lodestoneIdChanged)
Q_PROPERTY(AccountConfig *config READ config CONSTANT)
Q_PROPERTY(QString avatarUrl READ avatarUrl NOTIFY avatarUrlChanged)
Q_PROPERTY(bool isSapphire READ isSapphire WRITE setIsSapphire NOTIFY isSapphireChanged)
Q_PROPERTY(QString lobbyUrl READ lobbyUrl WRITE setLobbyUrl NOTIFY lobbyUrlChanged)
Q_PROPERTY(bool rememberPassword READ rememberPassword WRITE setRememberPassword NOTIFY rememberPasswordChanged)
Q_PROPERTY(bool rememberOTP READ rememberOTP WRITE setRememberOTP NOTIFY rememberOTPChanged)
Q_PROPERTY(bool useOTP READ useOTP WRITE setUseOTP NOTIFY useOTPChanged)
Q_PROPERTY(GameLicense license READ license WRITE setLicense NOTIFY licenseChanged)
Q_PROPERTY(bool isFreeTrial READ isFreeTrial WRITE setIsFreeTrial NOTIFY isFreeTrialChanged)
Q_PROPERTY(bool needsPassword READ needsPassword NOTIFY needsPasswordChanged)
public:
explicit Account(const QString &key, QObject *parent = nullptr);
enum class GameLicense { WindowsStandalone, WindowsSteam, macOS };
enum GameLicense {
WindowsStandalone,
WindowsSteam,
macOS
};
Q_ENUM(GameLicense)
[[nodiscard]] QString uuid() const;
[[nodiscard]] QString name() const;
void setName(const QString &name);
[[nodiscard]] int language() const;
void setLanguage(int value);
[[nodiscard]] QString lodestoneId() const;
void setLodestoneId(const QString &id);
[[nodiscard]] QString avatarUrl() const;
[[nodiscard]] bool isSapphire() const;
void setIsSapphire(bool value);
[[nodiscard]] QString lobbyUrl() const;
void setLobbyUrl(const QString &url);
[[nodiscard]] bool rememberPassword() const;
void setRememberPassword(bool value);
[[nodiscard]] bool rememberOTP() const;
void setRememberOTP(bool value);
[[nodiscard]] bool useOTP() const;
void setUseOTP(bool value);
[[nodiscard]] GameLicense license() const;
void setLicense(GameLicense license);
[[nodiscard]] bool isFreeTrial() const;
void setIsFreeTrial(bool value);
Q_INVOKABLE QString getPassword();
void setPassword(const QString &password);
@ -81,18 +46,10 @@ public:
[[nodiscard]] bool needsPassword() const;
AccountConfig *config() const;
Q_SIGNALS:
void nameChanged();
void languageChanged();
void lodestoneIdChanged();
void avatarUrlChanged();
void isSapphireChanged();
void lobbyUrlChanged();
void rememberPasswordChanged();
void rememberOTPChanged();
void useOTPChanged();
void licenseChanged();
void isFreeTrialChanged();
bool needsPasswordChanged();
private:
@ -108,7 +65,7 @@ private:
*/
QCoro::Task<QString> getKeychainValue(const QString &key);
AccountConfig m_config;
AccountConfig *m_config;
QString m_key;
QString m_avatarUrl;
bool m_needsPassword = false;

View file

@ -7,6 +7,7 @@
#include <qcorocore.h>
#include <qt6keychain/keychain.h>
#include "accountconfig.h"
#include "astra_log.h"
#include "utility.h"
@ -14,7 +15,7 @@ using namespace Qt::StringLiterals;
Account::Account(const QString &key, QObject *parent)
: QObject(parent)
, m_config(key)
, m_config(new AccountConfig(key))
, m_key(key)
{
fetchPassword();
@ -25,151 +26,11 @@ QString Account::uuid() const
return m_key;
}
QString Account::name() const
{
return m_config.name();
}
void Account::setName(const QString &name)
{
if (m_config.name() != name) {
m_config.setName(name);
m_config.save();
Q_EMIT nameChanged();
}
}
int Account::language() const
{
return m_config.language();
}
void Account::setLanguage(const int value)
{
if (m_config.language() != value) {
m_config.setLanguage(value);
m_config.save();
Q_EMIT languageChanged();
}
}
QString Account::lodestoneId() const
{
return m_config.lodestoneId();
}
void Account::setLodestoneId(const QString &id)
{
if (m_config.lodestoneId() != id) {
m_config.setLodestoneId(id);
m_config.save();
Q_EMIT lodestoneIdChanged();
}
}
QString Account::avatarUrl() const
{
return m_avatarUrl;
}
bool Account::isSapphire() const
{
return m_config.isSapphire();
}
void Account::setIsSapphire(const bool value)
{
if (m_config.isSapphire() != value) {
m_config.setIsSapphire(value);
m_config.save();
Q_EMIT isSapphireChanged();
}
}
QString Account::lobbyUrl() const
{
return m_config.lobbyUrl();
}
void Account::setLobbyUrl(const QString &url)
{
if (m_config.lobbyUrl() != url) {
m_config.setLobbyUrl(url);
m_config.save();
Q_EMIT lobbyUrlChanged();
}
}
bool Account::rememberPassword() const
{
return m_config.rememberPassword();
}
void Account::setRememberPassword(const bool value)
{
if (m_config.rememberPassword() != value) {
m_config.setRememberPassword(value);
m_config.save();
Q_EMIT rememberPasswordChanged();
}
}
bool Account::rememberOTP() const
{
return m_config.rememberOTP();
}
void Account::setRememberOTP(const bool value)
{
if (m_config.rememberOTP() != value) {
m_config.setRememberOTP(value);
m_config.save();
Q_EMIT rememberOTPChanged();
}
}
bool Account::useOTP() const
{
return m_config.useOTP();
}
void Account::setUseOTP(const bool value)
{
if (m_config.useOTP() != value) {
m_config.setUseOTP(value);
m_config.save();
Q_EMIT useOTPChanged();
}
}
Account::GameLicense Account::license() const
{
return static_cast<GameLicense>(m_config.license());
}
void Account::setLicense(const GameLicense license)
{
if (static_cast<GameLicense>(m_config.license()) != license) {
m_config.setLicense(static_cast<int>(license));
m_config.save();
Q_EMIT licenseChanged();
}
}
bool Account::isFreeTrial() const
{
return m_config.isFreeTrial();
}
void Account::setIsFreeTrial(const bool value)
{
if (m_config.isFreeTrial() != value) {
m_config.setIsFreeTrial(value);
m_config.save();
Q_EMIT isFreeTrialChanged();
}
}
QString Account::getPassword()
{
return QCoro::waitFor(getKeychainValue(QStringLiteral("password")));
@ -291,4 +152,9 @@ QCoro::Task<> Account::fetchPassword()
co_return;
}
AccountConfig *Account::config() const
{
return m_config;
}
#include "moc_account.cpp"

View file

@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#include "accountmanager.h"
#include "accountconfig.h"
#include "astra_log.h"
#include <KSharedConfig>
@ -57,10 +58,10 @@ QHash<int, QByteArray> AccountManager::roleNames() const
Account *AccountManager::createSquareEnixAccount(const QString &username, const int licenseType, const bool isFreeTrial)
{
const auto account = new Account(QUuid::createUuid().toString(), this);
account->setIsSapphire(false);
account->setLicense(static_cast<Account::GameLicense>(licenseType));
account->setIsFreeTrial(isFreeTrial);
account->setName(username);
account->config()->setIsSapphire(false);
account->config()->setLicense(static_cast<Account::GameLicense>(licenseType));
account->config()->setIsFreeTrial(isFreeTrial);
account->config()->setName(username);
insertAccount(account);
@ -70,9 +71,9 @@ Account *AccountManager::createSquareEnixAccount(const QString &username, const
Account *AccountManager::createSapphireAccount(const QString &lobbyUrl, const QString &username)
{
const auto account = new Account(QUuid::createUuid().toString(), this);
account->setIsSapphire(true);
account->setName(username);
account->setLobbyUrl(lobbyUrl);
account->config()->setIsSapphire(true);
account->config()->setName(username);
account->config()->setLobbyUrl(lobbyUrl);
insertAccount(account);

View file

@ -7,6 +7,7 @@
#include <gamemode_client.h>
#endif
#include "accountconfig.h"
#include "astra_log.h"
#include "encryptedarg.h"
#include "launchercore.h"
@ -156,7 +157,7 @@ void GameRunner::beginDalamudGame(const QString &gameExecutablePath, Profile &pr
QStringLiteral("--dalamud-configuration-path=") + Utility::toWindowsPath(dalamudConfigPath),
QStringLiteral("--dalamud-plugin-directory=") + Utility::toWindowsPath(dalamudPluginDir),
QStringLiteral("--dalamud-asset-directory=") + Utility::toWindowsPath(dalamudAssetDir),
QStringLiteral("--dalamud-client-language=") + QString::number(profile.account()->language()),
QStringLiteral("--dalamud-client-language=") + QString::number(profile.account()->config()->language()),
QStringLiteral("--dalamud-delay-initialize=") + QString::number(profile.dalamudInjectDelay()),
QStringLiteral("--logpath=") + Utility::toWindowsPath(logDir),
QStringLiteral("--"),
@ -206,7 +207,7 @@ QString GameRunner::getGameArgs(const Profile &profile, const std::optional<Logi
gameArgs.push_back({QStringLiteral("DEV.UseSqPack"), QString::number(1)});
gameArgs.push_back({QStringLiteral("ver"), profile.baseGameVersion()});
gameArgs.push_back({QStringLiteral("resetconfig"), QStringLiteral("0")});
gameArgs.push_back({QStringLiteral("language"), QString::number(profile.account()->language())});
gameArgs.push_back({QStringLiteral("language"), QString::number(profile.account()->config()->language())});
gameArgs.push_back({QStringLiteral("UserPath"), Utility::toWindowsPath(profile.account()->getConfigDir().absolutePath())});
Utility::createPathIfNeeded(profile.account()->getConfigDir().absolutePath());
@ -236,7 +237,7 @@ QString GameRunner::getGameArgs(const Profile &profile, const std::optional<Logi
}
}
if (profile.account()->license() == Account::GameLicense::WindowsSteam) {
if (profile.account()->config()->license() == Account::GameLicense::WindowsSteam) {
gameArgs.push_back({QStringLiteral("IsSteam"), QString::number(1)});
}
}
@ -260,7 +261,7 @@ void GameRunner::launchExecutable(const Profile &profile, QProcess *process, con
#if defined(Q_OS_LINUX) || defined(Q_OS_MAC)
// FFXIV detects this as a "macOS" build by checking if Wine shows up
if (!profile.isBenchmark()) {
const int value = profile.account()->license() == Account::GameLicense::macOS ? 0 : 1;
const int value = profile.account()->config()->license() == Account::GameLicense::macOS ? 0 : 1;
addRegistryKey(profile, QStringLiteral("HKEY_CURRENT_USER\\Software\\Wine"), QStringLiteral("HideWineExports"), QString::number(value));
}
@ -348,7 +349,7 @@ void GameRunner::launchExecutable(const Profile &profile, QProcess *process, con
arguments.push_back(profile.winePath());
#endif
if (!profile.isBenchmark() && profile.account()->license() == Account::GameLicense::WindowsSteam) {
if (!profile.isBenchmark() && profile.account()->config()->license() == Account::GameLicense::WindowsSteam) {
env.insert(QStringLiteral("IS_FFXIV_LAUNCH_FROM_STEAM"), QStringLiteral("1"));
}

View file

@ -12,6 +12,7 @@
#include <qcoronetworkreply.h>
#include "account.h"
#include "accountconfig.h"
#include "assetupdater.h"
#include "astra_log.h"
#include "benchmarkinstaller.h"
@ -100,7 +101,7 @@ void LauncherCore::login(Profile *profile, const QString &username, const QStrin
loginInformation->password = password;
loginInformation->oneTimePassword = oneTimePassword;
if (profile->account()->rememberPassword()) {
if (profile->account()->config()->rememberPassword()) {
profile->account()->setPassword(password);
}
}
@ -113,8 +114,8 @@ bool LauncherCore::autoLogin(Profile *profile)
Q_ASSERT(profile != nullptr);
QString otp;
if (profile->account()->useOTP()) {
if (!profile->account()->rememberOTP()) {
if (profile->account()->config()->useOTP()) {
if (!profile->account()->config()->rememberOTP()) {
Q_EMIT loginError(i18n("This account does not have an OTP secret set, but requires it for login."));
return false;
}
@ -126,7 +127,7 @@ bool LauncherCore::autoLogin(Profile *profile)
}
}
login(profile, profile->account()->name(), profile->account()->getPassword(), otp);
login(profile, profile->account()->config()->name(), profile->account()->getPassword(), otp);
return true;
}
@ -172,21 +173,21 @@ BenchmarkInstaller *LauncherCore::createBenchmarkInstallerFromExisting(Profile *
void LauncherCore::fetchAvatar(Account *account)
{
if (account->lodestoneId().isEmpty()) {
if (account->config()->lodestoneId().isEmpty()) {
return;
}
const QString cacheLocation = QStandardPaths::standardLocations(QStandardPaths::CacheLocation)[0] + QStringLiteral("/avatars");
Utility::createPathIfNeeded(cacheLocation);
const QString filename = QStringLiteral("%1/%2.jpg").arg(cacheLocation, account->lodestoneId());
const QString filename = QStringLiteral("%1/%2.jpg").arg(cacheLocation, account->config()->lodestoneId());
if (!QFile(filename).exists()) {
qDebug(ASTRA_LOG) << "Did not find lodestone character " << account->lodestoneId() << " in cache, fetching from Lodestone.";
qDebug(ASTRA_LOG) << "Did not find lodestone character " << account->config()->lodestoneId() << " in cache, fetching from Lodestone.";
QUrl url;
url.setScheme(config()->preferredProtocol());
url.setHost(QStringLiteral("na.%1").arg(config()->mainServer())); // TODO: NA isnt the only thing in the world...
url.setPath(QStringLiteral("/lodestone/character/%1").arg(account->lodestoneId()));
url.setPath(QStringLiteral("/lodestone/character/%1").arg(account->config()->lodestoneId()));
const QNetworkRequest request(url);
Utility::printRequest(QStringLiteral("GET"), request);
@ -347,7 +348,7 @@ void LauncherCore::buildRequest(const Profile &settings, QNetworkRequest &reques
{
Utility::setSSL(request);
if (settings.account()->license() == Account::GameLicense::macOS) {
if (settings.account()->config()->license() == Account::GameLicense::macOS) {
request.setHeader(QNetworkRequest::UserAgentHeader, QByteArrayLiteral("macSQEXAuthor/2.0.0(MacOSX; ja-jp)"));
} else {
request.setHeader(QNetworkRequest::UserAgentHeader,
@ -468,8 +469,8 @@ QCoro::Task<> LauncherCore::beginLogin(LoginInformation &info)
std::optional<LoginAuth> auth;
if (!info.profile->isBenchmark()) {
if (info.profile->account()->isSapphire()) {
auth = co_await m_sapphireLogin->login(info.profile->account()->lobbyUrl(), info);
if (info.profile->account()->config()->isSapphire()) {
auth = co_await m_sapphireLogin->login(info.profile->account()->config()->lobbyUrl(), info);
} else {
auth = co_await m_squareEnixLogin->login(&info);
}

View file

@ -14,6 +14,7 @@
#include <qcoronetworkreply.h>
#include "account.h"
#include "accountconfig.h"
#include "astra_log.h"
#include "launchercore.h"
#include "utility.h"
@ -176,7 +177,7 @@ QCoro::Task<bool> SquareEnixLogin::checkBootUpdates()
url.setQuery(query);
auto request = QNetworkRequest(url);
if (m_info->profile->account()->license() == Account::GameLicense::macOS) {
if (m_info->profile->account()->config()->license() == Account::GameLicense::macOS) {
request.setHeader(QNetworkRequest::KnownHeaders::UserAgentHeader, macosPatchUserAgent);
} else {
request.setHeader(QNetworkRequest::KnownHeaders::UserAgentHeader, patchUserAgent);
@ -225,12 +226,12 @@ QCoro::Task<std::optional<SquareEnixLogin::StoredInfo>> SquareEnixLogin::getStor
query.addQueryItem(QStringLiteral("lng"), QStringLiteral("en"));
// for some reason, we always use region 3. the actual region is acquired later
query.addQueryItem(QStringLiteral("rgn"), QString::number(3));
query.addQueryItem(QStringLiteral("isft"), QString::number(m_info->profile->account()->isFreeTrial() ? 1 : 0));
query.addQueryItem(QStringLiteral("isft"), QString::number(m_info->profile->account()->config()->isFreeTrial() ? 1 : 0));
query.addQueryItem(QStringLiteral("cssmode"), QString::number(1));
query.addQueryItem(QStringLiteral("isnew"), QString::number(1));
query.addQueryItem(QStringLiteral("launchver"), QString::number(3));
if (m_info->profile->account()->license() == Account::GameLicense::WindowsSteam) {
if (m_info->profile->account()->config()->license() == Account::GameLicense::WindowsSteam) {
query.addQueryItem(QStringLiteral("issteam"), QString::number(1));
// TODO: get steam ticket information from steam api
@ -255,7 +256,7 @@ QCoro::Task<std::optional<SquareEnixLogin::StoredInfo>> SquareEnixLogin::getStor
const QString str = QString::fromUtf8(reply->readAll());
// fetches Steam username
if (m_info->profile->account()->license() == Account::GameLicense::WindowsSteam) {
if (m_info->profile->account()->config()->license() == Account::GameLicense::WindowsSteam) {
const static QRegularExpression re(QStringLiteral(R"lit(<input name=""sqexid"" type=""hidden"" value=""(?<sqexid>.*)""\/>)lit"));
const QRegularExpressionMatch match = re.match(str);

View file

@ -31,7 +31,7 @@ QQC2.Control {
return i18n("Password is required.");
}
if (LauncherCore.currentProfile.account.useOTP && !LauncherCore.currentProfile.account.rememberOTP && otpField.text.length === 0) {
if (LauncherCore.currentProfile.account.config.useOTP && !LauncherCore.currentProfile.account.config.rememberOTP && otpField.text.length === 0) {
return i18n("OTP is required.");
}
@ -55,7 +55,7 @@ QQC2.Control {
return false;
}
if (LauncherCore.currentProfile.account.useOTP && !LauncherCore.currentProfile.account.rememberOTP && otpField.text.length === 0) {
if (LauncherCore.currentProfile.account.config.useOTP && !LauncherCore.currentProfile.account.config.rememberOTP && otpField.text.length === 0) {
return false;
}
@ -63,9 +63,9 @@ QQC2.Control {
}
function updateFields(): void {
usernameField.text = LauncherCore.currentProfile.account.name;
passwordField.text = !LauncherCore.currentProfile.account.needsPassword && LauncherCore.currentProfile.account.rememberPassword ? LauncherCore.currentProfile.account.getPassword() : "";
if (LauncherCore.currentProfile.account.rememberOTP) {
usernameField.text = LauncherCore.currentProfile.account.config.name;
passwordField.text = !LauncherCore.currentProfile.account.needsPassword && LauncherCore.currentProfile.account.config.rememberPassword ? LauncherCore.currentProfile.account.getPassword() : "";
if (LauncherCore.currentProfile.account.config.rememberOTP) {
otpField.text = "Auto-generated";
} else {
otpField.text = "";
@ -83,7 +83,7 @@ QQC2.Control {
return;
}
if (LauncherCore.currentProfile.account.useOTP) {
if (LauncherCore.currentProfile.account.config.useOTP) {
otpField.forceActiveFocus();
return;
}
@ -165,13 +165,13 @@ QQC2.Control {
id: currentAccountDelegate
enabled: LauncherCore.accountManager.numAccounts > 1
text: LauncherCore.currentProfile.account.name
text: LauncherCore.currentProfile.account.config.name
leading: Components.Avatar {
implicitWidth: Kirigami.Units.iconSizes.medium
implicitHeight: Kirigami.Units.iconSizes.medium
name: LauncherCore.currentProfile.account.name
name: LauncherCore.currentProfile.account.config.name
source: LauncherCore.currentProfile.account.avatarUrl
}
@ -191,7 +191,7 @@ QQC2.Control {
required property var account
QQC2.MenuItem {
text: menuItem.account.name
text: menuItem.account.config.name
icon.name: menuItem.account.avatarUrl.length === 0 ? "actor" : ""
icon.source: menuItem.account.avatarUrl
@ -214,8 +214,8 @@ QQC2.Control {
FormCard.FormTextFieldDelegate {
id: usernameField
label: LauncherCore.currentProfile.account.isSapphire ? i18n("Username") : i18n("Square Enix ID")
text: LauncherCore.currentProfile.account.name
label: LauncherCore.currentProfile.account.config.isSapphire ? i18n("Username") : i18n("Square Enix ID")
text: LauncherCore.currentProfile.account.config.name
enabled: false
QQC2.ToolTip.text: i18n("The username can only be changed under account settings.")
@ -230,7 +230,7 @@ QQC2.Control {
FormCard.FormPasswordFieldDelegate {
id: passwordField
label: LauncherCore.currentProfile.account.isSapphire ? i18n("Password") : i18n("Square Enix Password")
label: LauncherCore.currentProfile.account.config.isSapphire ? i18n("Password") : i18n("Square Enix Password")
focus: true
onAccepted: {
if (otpField.visible) {
@ -243,15 +243,15 @@ QQC2.Control {
FormCard.FormDelegateSeparator {
above: passwordField
below: LauncherCore.currentProfile.account.useOTP ? otpField : loginButton
below: LauncherCore.currentProfile.account.config.useOTP ? otpField : loginButton
}
FormCard.FormTextFieldDelegate {
id: otpField
enabled: !LauncherCore.currentProfile.account.rememberOTP
enabled: !LauncherCore.currentProfile.account.config.rememberOTP
label: i18n("One-time Password")
visible: LauncherCore.currentProfile.account.useOTP
visible: LauncherCore.currentProfile.account.config.useOTP
onAccepted: {
if (page.isLoginValid) {
loginButton.clicked()
@ -260,9 +260,9 @@ QQC2.Control {
}
FormCard.FormDelegateSeparator {
above: LauncherCore.currentProfile.account.useOTP ? otpField : passwordField
above: LauncherCore.currentProfile.account.config.useOTP ? otpField : passwordField
below: loginButton
visible: LauncherCore.currentProfile.account.useOTP
visible: LauncherCore.currentProfile.account.config.useOTP
}
FormCard.FormButtonDelegate {
@ -281,7 +281,7 @@ QQC2.Control {
FormCard.FormDelegateSeparator {
above: loginButton
below: forgotPasswordButton
visible: !LauncherCore.currentProfile.account.isSapphire
visible: !LauncherCore.currentProfile.account.config.isSapphire
}
FormCard.FormButtonDelegate {
@ -289,7 +289,7 @@ QQC2.Control {
text: i18n("Forgot ID or Password")
icon.name: "question-symbolic"
visible: !LauncherCore.currentProfile.account.isSapphire
visible: !LauncherCore.currentProfile.account.config.isSapphire
onClicked: applicationWindow().openUrl('https://secure.square-enix.com/account/app/svc/reminder')
}
}
@ -325,7 +325,7 @@ QQC2.Control {
FormCard.FormLinkDelegate {
text: i18nc("@action:button", "The Lodestone")
icon.name: "internet-services-symbolic"
visible: !LauncherCore.currentProfile.account.isSapphire
visible: !LauncherCore.currentProfile.account.config.isSapphire
// TODO: how do we link to a "worldwide" lodestone, if that even exists?
url: 'https://na.finalfantasyxiv.com/lodestone/'
onClicked: applicationWindow().openUrl(url)
@ -336,7 +336,7 @@ QQC2.Control {
FormCard.FormLinkDelegate {
text: i18nc("@action:button", "Mog Station")
icon.name: "internet-services-symbolic"
visible: !LauncherCore.currentProfile.account.isSapphire
visible: !LauncherCore.currentProfile.account.config.isSapphire
url: 'https://secure.square-enix.com/account/app/svc/mogstation/'
onClicked: applicationWindow().openUrl(url)
}

View file

@ -67,8 +67,8 @@ FormCard.FormCardPage {
id: usernameDelegate
label: i18n("Username")
text: page.account.name
onTextChanged: page.account.name = text
text: page.account.config.name
onTextChanged: page.account.config.name = text
}
FormCard.FormDelegateSeparator {
@ -81,8 +81,8 @@ FormCard.FormCardPage {
text: i18n("Account type")
model: ["Square Enix", "Sapphire"]
currentIndex: page.account.isSapphire ? 1 : 0
onCurrentIndexChanged: page.account.isSapphire = (currentIndex === 1)
currentIndex: page.account.config.isSapphire ? 1 : 0
onCurrentIndexChanged: page.account.config.isSapphire = (currentIndex === 1)
}
FormCard.FormDelegateSeparator {
@ -96,13 +96,13 @@ FormCard.FormCardPage {
text: i18n("Language")
description: i18n("The language used in the game client.")
model: ["Japanese", "English", "German", "French"]
currentIndex: page.account.language
onCurrentIndexChanged: page.account.language = currentIndex
currentIndex: page.account.config.language
onCurrentIndexChanged: page.account.config.language = currentIndex
}
}
FormCard.FormCard {
visible: accountAction.checked && !page.account.isSapphire
visible: accountAction.checked && !page.account.config.isSapphire
Layout.fillWidth: true
Layout.topMargin: Kirigami.Units.largeSpacing * 4
@ -113,8 +113,8 @@ FormCard.FormCardPage {
text: i18n("License")
description: i18n("If the account holds multiple licenses, choose the preferred one.")
model: ["Windows", "Steam", "macOS"]
currentIndex: page.account.license
onCurrentIndexChanged: page.account.license = currentIndex
currentIndex: page.account.config.license
onCurrentIndexChanged: page.account.config.license = currentIndex
}
FormCard.FormDelegateSeparator {
@ -126,8 +126,8 @@ FormCard.FormCardPage {
id: freeTrialField
text: i18n("Free trial")
description: i18n("If the account has a free trial license.")
checked: page.account.isFreeTrial
onCheckedChanged: page.account.isFreeTrial = checked
checked: page.account.config.isFreeTrial
onCheckedChanged: page.account.config.isFreeTrial = checked
}
FormCard.FormDelegateSeparator {
@ -140,8 +140,8 @@ FormCard.FormCardPage {
text: i18n("Needs a one-time password")
description: i18n("Prompt for the one-time password when logging in.")
checked: page.account.useOTP
onCheckedChanged: page.account.useOTP = checked
checked: page.account.config.useOTP
onCheckedChanged: page.account.config.useOTP = checked
}
FormCard.FormDelegateSeparator {
@ -161,11 +161,11 @@ FormCard.FormCardPage {
standardButtons: Kirigami.Dialog.Ok | Kirigami.Dialog.Cancel
onAccepted: page.account.lodestoneId = lodestoneIdField.text
onAccepted: page.account.config.lodestoneId = lodestoneIdField.text
QQC2.TextField {
id: lodestoneIdField
text: page.account.lodestoneId
text: page.account.config.lodestoneId
placeholderText: qsTr("123456...")
}
}
@ -175,7 +175,7 @@ FormCard.FormCardPage {
}
FormCard.FormCard {
visible: accountAction.checked && page.account.isSapphire
visible: accountAction.checked && page.account.config.isSapphire
Layout.fillWidth: true
Layout.topMargin: Kirigami.Units.largeSpacing * 4
@ -184,9 +184,9 @@ FormCard.FormCardPage {
id: lobbyURLDelegate
label: i18n("Lobby URL")
text: page.account.lobbyUrl
onTextChanged: page.account.lobbyUrl = text
visible: page.account.isSapphire
text: page.account.config.lobbyUrl
onTextChanged: page.account.config.lobbyUrl = text
visible: page.account.config.isSapphire
placeholderText: "neolobby0X.ffxiv.com"
}
}
@ -202,8 +202,8 @@ FormCard.FormCardPage {
text: i18n("Remember password")
description: i18n("Stores the password on the device, using it's existing secure credential storage.")
checked: page.account.rememberPassword
onCheckedChanged: page.account.rememberPassword = checked
checked: page.account.config.rememberPassword
onCheckedChanged: page.account.config.rememberPassword = checked
}
FormCard.FormDelegateSeparator {
@ -217,10 +217,10 @@ FormCard.FormCardPage {
text: i18n("Automatically generate one-time passwords")
description: i18n("Stores the one-time password secret on this device, making it inherently insecure. Only use this feature if you understand the risks.")
checked: page.account.rememberOTP
onCheckedChanged: page.account.rememberOTP = checked
enabled: page.account.useOTP
visible: !page.account.isSapphire
checked: page.account.config.rememberOTP
onCheckedChanged: page.account.config.rememberOTP = checked
enabled: page.account.config.useOTP
visible: !page.account.config.isSapphire
}
FormCard.FormDelegateSeparator {
@ -235,7 +235,7 @@ FormCard.FormCardPage {
text: i18n("Enter OTP Secret")
icon.name: "list-add-symbolic"
enabled: page.account.rememberOTP
enabled: page.account.config.rememberOTP
visible: generateOTPField.visible
Kirigami.PromptDialog {
id: otpDialog

View file

@ -52,12 +52,12 @@ FormCard.FormCardPage {
spacing: 0
FormCard.FormButtonDelegate {
text: layout.account.name
description: layout.account.isSapphire ? i18n("Sapphire") : i18n("Square Enix")
text: layout.account.config.name
description: layout.account.config.isSapphire ? i18n("Sapphire") : i18n("Square Enix")
leading: Components.Avatar
{
name: layout.account.name
name: layout.account.config.name
source: layout.account.avatarUrl
}

View file

@ -45,7 +45,7 @@ FormCard.FormCardPage {
FormCard.FormButtonDelegate {
required property var account
text: account.name
text: account.config.name
onClicked: {
page.profile.account = account