Qt: Add Register button for achievements

And fix a potential deadlock.
This commit is contained in:
Stenzek
2026-06-28 20:07:14 +10:00
parent a9cc936baf
commit ffd9d40d65
10 changed files with 85 additions and 26 deletions
+3 -3
View File
@@ -2774,7 +2774,7 @@ const char* Settings::GetPIODeviceTypeModeDisplayName(PIODeviceType type)
namespace EmuFolders {
static void EnsureFolderExists(const std::string& path);
static std::string LoadPathFromSettings(SettingsInterface& si, const std::string& root, const char* section,
static std::string LoadPathFromSettings(const SettingsInterface& si, const std::string& root, const char* section,
const char* name, const char* def);
std::string AppRoot;
@@ -2844,7 +2844,7 @@ void EmuFolders::SetDefaults()
Videos = Path::Combine(DataRoot, "videos");
}
std::string EmuFolders::LoadPathFromSettings(SettingsInterface& si, const std::string& root, const char* section,
std::string EmuFolders::LoadPathFromSettings(const SettingsInterface& si, const std::string& root, const char* section,
const char* name, const char* def)
{
std::string value = si.GetStringValue(section, name, def);
@@ -2856,7 +2856,7 @@ std::string EmuFolders::LoadPathFromSettings(SettingsInterface& si, const std::s
return value;
}
void EmuFolders::LoadConfig(SettingsInterface& si)
void EmuFolders::LoadConfig(const SettingsInterface& si)
{
Bios = LoadPathFromSettings(si, DataRoot, "BIOS", "SearchDirectory", "bios");
Cache = LoadPathFromSettings(si, DataRoot, "Folders", "Cache", "cache");
+1 -1
View File
@@ -687,7 +687,7 @@ extern std::string Videos;
// Assumes that AppRoot and DataRoot have been initialized.
void SetDefaults();
void EnsureFoldersExist();
void LoadConfig(SettingsInterface& si);
void LoadConfig(const SettingsInterface& si);
void Save(SettingsInterface& si);
// Returns the default path for the given settings key.
@@ -136,7 +136,9 @@ AchievementSettingsWidget::AchievementSettingsWidget(SettingsWindow* dialog, QWi
if (!m_dialog->isPerGameSettings())
{
connect(m_ui.loginButton, &QPushButton::clicked, this, &AchievementSettingsWidget::onLoginLogoutPressed);
connect(m_ui.login, &QPushButton::clicked, this, &AchievementSettingsWidget::onLoginPressed);
connect(m_ui.logout, &QPushButton::clicked, this, &AchievementSettingsWidget::onLogoutPressed);
connect(m_ui.registerUser, &QPushButton::clicked, this, &AchievementSettingsWidget::onRegisterUserPressed);
connect(m_ui.viewProfile, &QPushButton::clicked, this, &AchievementSettingsWidget::onViewProfilePressed);
connect(g_core_thread, &CoreThread::achievementsLoginSuccess, this, &AchievementSettingsWidget::updateLoginState);
updateLoginState();
@@ -317,31 +319,45 @@ void AchievementSettingsWidget::updateLoginState()
const QString login_timestamp =
QtHost::FormatNumber(Host::NumberFormatType::ShortDateTime, static_cast<s64>(login_unix_timestamp));
m_ui.loginStatus->setText(tr("Logged in as %1\nToken generated at %2").arg(qusername).arg(login_timestamp));
m_ui.loginButton->setText(tr("Logout"));
}
else
{
m_ui.loginStatus->setText(tr("Not Logged In."));
m_ui.loginButton->setText(tr("Login..."));
}
m_ui.viewProfile->setVisible(logged_in);
m_ui.viewProfile->setEnabled(logged_in);
m_ui.logout->setVisible(logged_in);
m_ui.logout->setEnabled(logged_in);
m_ui.registerUser->setVisible(!logged_in);
m_ui.registerUser->setEnabled(!logged_in);
m_ui.login->setVisible(!logged_in);
m_ui.login->setEnabled(!logged_in);
}
void AchievementSettingsWidget::onLoginLogoutPressed()
void AchievementSettingsWidget::onLoginPressed()
{
if (!Core::GetBaseStringSettingValue("Cheevos", "Username").empty())
{
Host::RunOnCoreThread([]() { Achievements::Logout(); }, true);
updateLoginState();
return;
}
AchievementLoginDialog* login = new AchievementLoginDialog(this, Achievements::LoginRequestReason::UserInitiated);
connect(login, &AchievementLoginDialog::accepted, this, &AchievementSettingsWidget::onLoginCompleted);
login->open();
}
void AchievementSettingsWidget::onLogoutPressed()
{
if (Core::GetBaseStringSettingValue("Cheevos", "Username").empty())
return;
Host::RunOnCoreThread([]() {
Achievements::Logout();
Host::RunOnUIThread([]() {
SettingsWindow* settings = g_main_window ? g_main_window->getSettingsWindow() : nullptr;
AchievementSettingsWidget* achievement_settings = settings ? settings->getAchievementSettingsWidget() : nullptr;
if (achievement_settings)
achievement_settings->updateLoginState();
});
});
}
void AchievementSettingsWidget::onLoginCompleted()
{
updateLoginState();
@@ -356,6 +372,11 @@ void AchievementSettingsWidget::onLoginCompleted()
m_ui.hardcoreMode->setChecked(true);
}
void AchievementSettingsWidget::onRegisterUserPressed()
{
QtUtils::OpenURL(this, QUrl(QStringLiteral("https://retroachievements.org/createaccount.php")));
}
void AchievementSettingsWidget::onViewProfilePressed()
{
const std::string username(Core::GetBaseStringSettingValue("Cheevos", "Username"));
@@ -26,8 +26,10 @@ private:
void onHardcoreModeStateChanged();
void onAchievementsNotificationDurationSliderChanged();
void onLeaderboardsNotificationDurationSliderChanged();
void onLoginLogoutPressed();
void onLoginPressed();
void onLogoutPressed();
void onLoginCompleted();
void onRegisterUserPressed();
void onViewProfilePressed();
Ui::AchievementSettingsWidget m_ui;
@@ -25,7 +25,7 @@
</property>
<item>
<widget class="QGroupBox" name="loginBox">
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,1,0,0">
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,1,0,0,0,0">
<property name="spacing">
<number>10</number>
</property>
@@ -61,6 +61,17 @@
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="registerUser">
<property name="text">
<string>Register</string>
</property>
<property name="icon">
<iconset resource="resources/duckstation-qt.qrc">
<normaloff>:/icons/monochrome/svg/user-add-line.svg</normaloff>:/icons/monochrome/svg/user-add-line.svg</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="viewProfile">
<property name="text">
@@ -73,7 +84,7 @@
</widget>
</item>
<item>
<widget class="QPushButton" name="loginButton">
<widget class="QPushButton" name="login">
<property name="text">
<string>Login...</string>
</property>
@@ -83,6 +94,17 @@
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="logout">
<property name="text">
<string>Logout</string>
</property>
<property name="icon">
<iconset resource="resources/duckstation-qt.qrc">
<normaloff>:/icons/monochrome/svg/logout-box-line.svg</normaloff>:/icons/monochrome/svg/logout-box-line.svg</iconset>
</property>
</widget>
</item>
</layout>
</widget>
</item>
@@ -132,6 +132,7 @@
<file>icons/monochrome/svg/lightbulb-line.svg</file>
<file>icons/monochrome/svg/list-check.svg</file>
<file>icons/monochrome/svg/login-box-line.svg</file>
<file>icons/monochrome/svg/logout-box-line.svg</file>
<file>icons/monochrome/svg/mag-line.svg</file>
<file>icons/monochrome/svg/memcard-line.svg</file>
<file>icons/monochrome/svg/memcards-line.svg</file>
@@ -167,6 +168,7 @@
<file>icons/monochrome/svg/trash-fill.svg</file>
<file>icons/monochrome/svg/trophy-line.svg</file>
<file>icons/monochrome/svg/tv-2-line.svg</file>
<file>icons/monochrome/svg/user-add-line.svg</file>
<file>icons/monochrome/svg/video-on-line.svg</file>
<file>icons/monochrome/svg/vidicon-line.svg</file>
<file>icons/monochrome/svg/volume-up-line.svg</file>
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M4 18H6V20H18V4H6V6H4V3C4 2.44772 4.44772 2 5 2H19C19.5523 2 20 2.44772 20 3V21C20 21.5523 19.5523 22 19 22H5C4.44772 22 4 21.5523 4 21V18ZM6 11H13V13H6V16L1 12L6 8V11Z"></path></svg>

After

Width:  |  Height:  |  Size: 272 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M14 14.252V16.3414C13.3744 16.1203 12.7013 16 12 16C8.68629 16 6 18.6863 6 22H4C4 17.5817 7.58172 14 12 14C12.6906 14 13.3608 14.0875 14 14.252ZM12 13C8.685 13 6 10.315 6 7C6 3.685 8.685 1 12 1C15.315 1 18 3.685 18 7C18 10.315 15.315 13 12 13ZM12 11C14.21 11 16 9.21 16 7C16 4.79 14.21 3 12 3C9.79 3 8 4.79 8 7C8 9.21 9.79 11 12 11ZM18 17V14H20V17H23V19H20V22H18V19H15V17H18Z"></path></svg>

After

Width:  |  Height:  |  Size: 479 B

+15 -5
View File
@@ -100,7 +100,7 @@ void SettingsWindow::addPages()
if (!isPerGameSettings())
{
addWidget(
m_game_list_settings = new GameListSettingsWidget(this, m_ui.settingsContainer), tr("Game List"),
new GameListSettingsWidget(this, m_ui.settingsContainer), tr("Game List"),
u":/icons/monochrome/svg/folder-open-line.svg"_s,
tr("<strong>Game List Settings</strong><hr>The list above shows the directories which will be searched by "
"DuckStation to populate the game list. Search directories can be added, removed, and switched to "
@@ -138,12 +138,11 @@ void SettingsWindow::addPages()
}
addWidget(
(m_memory_card_settings = new MemoryCardSettingsWidget(this, m_ui.settingsContainer)), tr("Memory Cards"),
new MemoryCardSettingsWidget(this, m_ui.settingsContainer), tr("Memory Cards"),
u":/icons/monochrome/svg/memcard-line.svg"_s,
tr("<strong>Memory Card Settings</strong><hr>This page lets you control what mode the memory card emulation will "
"function in, and where the images for these cards will be stored on disk."));
GraphicsSettingsWidget* graphics_settings;
addWidget(graphics_settings = new GraphicsSettingsWidget(this, m_ui.settingsContainer), tr("Graphics"),
addWidget(new GraphicsSettingsWidget(this, m_ui.settingsContainer), tr("Graphics"),
u":/icons/monochrome/svg/image-fill.svg"_s,
tr("<strong>Graphics Settings</strong><hr>These options control how the graphics of the emulated console "
"are rendered. Not all options are available for the software renderer. Mouse over each option for "
@@ -387,6 +386,16 @@ void SettingsWindow::onClearSettingsClicked()
tr("Per-game configuration cleared."));
}
GameListSettingsWidget* SettingsWindow::getGameListSettingsWidget() const
{
return findChild<GameListSettingsWidget*>();
}
AchievementSettingsWidget* SettingsWindow::getAchievementSettingsWidget() const
{
return findChild<AchievementSettingsWidget*>();
}
void SettingsWindow::registerWidgetHelp(QObject* object, QString title, QString recommended_value, QString text)
{
if (!object)
@@ -736,7 +745,8 @@ MultitapMode SettingsWindow::getEffectiveMultitapMode() const
void SettingsWindow::onMultitapModeChanged(MultitapMode mode)
{
m_memory_card_settings->createPortSettings(mode);
if (MemoryCardSettingsWidget* memcard_settings = findChild<MemoryCardSettingsWidget*>())
memcard_settings->createPortSettings(mode);
}
SettingsWindow* SettingsWindow::openGamePropertiesDialog(const GameList::Entry* entry,
+3 -3
View File
@@ -31,6 +31,7 @@ struct Entry;
class GameSummaryWidget;
class GameListSettingsWidget;
class MemoryCardSettingsWidget;
class AchievementSettingsWidget;
class SettingsWindow final : public QWidget
{
@@ -55,7 +56,8 @@ public:
ALWAYS_INLINE const GameDatabase::Entry* getDatabaseEntry() const { return m_database_entry; }
ALWAYS_INLINE bool hasDatabaseEntry() const { return (m_database_entry != nullptr); }
ALWAYS_INLINE GameListSettingsWidget* getGameListSettingsWidget() const { return m_game_list_settings; }
GameListSettingsWidget* getGameListSettingsWidget() const;
AchievementSettingsWidget* getAchievementSettingsWidget() const;
void registerWidgetHelp(QObject* object, QString title, QString recommended_value, QString text);
bool eventFilter(QObject* object, QEvent* event) override;
@@ -126,8 +128,6 @@ private:
const GameDatabase::Entry* m_database_entry = nullptr;
GameSummaryWidget* m_game_summary = nullptr;
GameListSettingsWidget* m_game_list_settings = nullptr;
MemoryCardSettingsWidget* m_memory_card_settings = nullptr;
std::array<QString, MAX_SETTINGS_WIDGETS> m_category_help_text;