feat: Add lobby API URL configuration and migrate from web_api_url

- Replace web_api_url references with lobby_api_url
- Add lobby API URL field to network configuration UI with restore default
- Add ReadNetworkValues/SaveNetworkValues to QtConfig for network settings
- Fix signed/unsigned comparison in lobby filter

Signed-off-by: Zephyron <zephyron@citron-emu.org>
This commit is contained in:
Zephyron
2025-12-06 16:38:45 +10:00
parent b5a82bcfdc
commit 2e7a4026d8
8 changed files with 81 additions and 14 deletions

View File

@@ -2,6 +2,7 @@
// SPDX-FileCopyrightText: Copyright 2025 Citron Emulator Project // SPDX-FileCopyrightText: Copyright 2025 Citron Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <QMessageBox>
#include <QtConcurrent/QtConcurrent> #include <QtConcurrent/QtConcurrent>
#include "common/settings.h" #include "common/settings.h"
#include "core/core.h" #include "core/core.h"
@@ -19,20 +20,26 @@ ConfigureNetwork::ConfigureNetwork(const Core::System& system_, QWidget* parent)
} }
this->SetConfiguration(); this->SetConfiguration();
// Store the initial URL
original_lobby_api_url = Settings::values.lobby_api_url.GetValue();
connect(ui->restore_default_lobby_api, &QPushButton::clicked, this, &ConfigureNetwork::OnRestoreDefaultLobbyApi);
} }
ConfigureNetwork::~ConfigureNetwork() = default; ConfigureNetwork::~ConfigureNetwork() = default;
void ConfigureNetwork::ApplyConfiguration() { void ConfigureNetwork::ApplyConfiguration() {
// Apply all settings from the UI to the settings system
Settings::values.airplane_mode = ui->airplane_mode->isChecked(); Settings::values.airplane_mode = ui->airplane_mode->isChecked();
Settings::values.network_interface = ui->network_interface->currentText().toStdString(); Settings::values.network_interface = ui->network_interface->currentText().toStdString();
Settings::values.lobby_api_url = ui->lobby_api_url->text().toStdString();
} }
void ConfigureNetwork::changeEvent(QEvent* event) { void ConfigureNetwork::changeEvent(QEvent* event) {
if (event->type() == QEvent::LanguageChange) { if (event->type() == QEvent::LanguageChange) {
RetranslateUI(); RetranslateUI();
} }
QWidget::changeEvent(event); QWidget::changeEvent(event);
} }
@@ -47,11 +54,23 @@ void ConfigureNetwork::SetConfiguration() {
ui->airplane_mode->setEnabled(runtime_lock); ui->airplane_mode->setEnabled(runtime_lock);
const std::string& network_interface = Settings::values.network_interface.GetValue(); const std::string& network_interface = Settings::values.network_interface.GetValue();
ui->network_interface->setCurrentText(QString::fromStdString(network_interface)); ui->network_interface->setCurrentText(QString::fromStdString(network_interface));
ui->network_interface->setEnabled(runtime_lock && !ui->airplane_mode->isChecked());
connect(ui->airplane_mode, &QCheckBox::toggled, this, [this](bool checked) { ui->lobby_api_url->setText(QString::fromStdString(Settings::values.lobby_api_url.GetValue()));
ui->network_interface->setEnabled(!checked && !system.IsPoweredOn());
const bool networking_enabled = runtime_lock && !ui->airplane_mode->isChecked();
ui->network_interface->setEnabled(networking_enabled);
ui->lobby_api_url->setEnabled(networking_enabled);
ui->restore_default_lobby_api->setEnabled(networking_enabled);
connect(ui->airplane_mode, &QCheckBox::toggled, this, [this, runtime_lock](bool checked) {
const bool enabled = !checked && runtime_lock;
ui->network_interface->setEnabled(enabled);
ui->lobby_api_url->setEnabled(enabled);
ui->restore_default_lobby_api->setEnabled(enabled);
}); });
} }
void ConfigureNetwork::OnRestoreDefaultLobbyApi() {
ui->lobby_api_url->setText(QString::fromStdString(Settings::values.lobby_api_url.GetDefault()));
}

View File

@@ -1,15 +1,22 @@
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-FileCopyrightText: 2025 citron Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
#include <memory> #include <memory>
#include <string> // Required for std::string
#include <QWidget> #include <QWidget>
namespace Ui { namespace Ui {
class ConfigureNetwork; class ConfigureNetwork;
} }
// Forward declare Core::System
namespace Core {
class System;
}
class ConfigureNetwork : public QWidget { class ConfigureNetwork : public QWidget {
Q_OBJECT Q_OBJECT
@@ -19,12 +26,17 @@ public:
void ApplyConfiguration(); void ApplyConfiguration();
private slots:
void OnRestoreDefaultLobbyApi();
private: private:
void changeEvent(QEvent*) override; void changeEvent(QEvent*) override;
void RetranslateUI(); void RetranslateUI();
void SetConfiguration(); void SetConfiguration();
std::unique_ptr<Ui::ConfigureNetwork> ui; std::unique_ptr<Ui::ConfigureNetwork> ui;
const Core::System& system; const Core::System& system;
// This stores the URL
std::string original_lobby_api_url;
}; };

View File

@@ -25,7 +25,7 @@
<string>General</string> <string>General</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout_2"> <layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0"> <item row="0" column="0" colspan="2">
<widget class="QCheckBox" name="airplane_mode"> <widget class="QCheckBox" name="airplane_mode">
<property name="text"> <property name="text">
<string>Airplane Mode</string> <string>Airplane Mode</string>
@@ -45,6 +45,23 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="0">
<widget class="QLabel" name="label_lobby_api">
<property name="text">
<string>Lobby API URL</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="lobby_api_url"/>
</item>
<item row="3" column="1">
<widget class="QPushButton" name="restore_default_lobby_api">
<property name="text">
<string>Restore Default</string>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>

View File

@@ -76,6 +76,7 @@ void QtConfig::ReadQtValues() {
ReadUIValues(); ReadUIValues();
} }
ReadQtControlValues(); ReadQtControlValues();
ReadNetworkValues();
} }
void QtConfig::ReadQtPlayerValues(const std::size_t player_index) { void QtConfig::ReadQtPlayerValues(const std::size_t player_index) {
@@ -279,6 +280,12 @@ void QtConfig::ReadUIValues() {
EndGroup(); EndGroup();
} }
void QtConfig::ReadNetworkValues() {
BeginGroup(Settings::TranslateCategory(Settings::Category::Network));
ReadCategory(Settings::Category::Network);
EndGroup();
}
void QtConfig::ReadUIGamelistValues() { void QtConfig::ReadUIGamelistValues() {
BeginGroup(Settings::TranslateCategory(Settings::Category::UiGameList)); BeginGroup(Settings::TranslateCategory(Settings::Category::UiGameList));
@@ -337,6 +344,7 @@ void QtConfig::SaveQtValues() {
LOG_DEBUG(Config, "Saving Qt configuration values"); LOG_DEBUG(Config, "Saving Qt configuration values");
} }
SaveQtControlValues(); SaveQtControlValues();
SaveNetworkValues();
WriteToIni(); WriteToIni();
} }
@@ -526,6 +534,12 @@ void QtConfig::SaveMultiplayerValues() {
EndGroup(); EndGroup();
} }
void QtConfig::SaveNetworkValues() {
BeginGroup(Settings::TranslateCategory(Settings::Category::Network));
WriteCategory(Settings::Category::Network);
EndGroup();
}
std::vector<Settings::BasicSetting*>& QtConfig::FindRelevantList(Settings::Category category) { std::vector<Settings::BasicSetting*>& QtConfig::FindRelevantList(Settings::Category category) {
auto& map = Settings::values.linkage.by_category; auto& map = Settings::values.linkage.by_category;
if (map.contains(category)) { if (map.contains(category)) {

View File

@@ -1,4 +1,5 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project // SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-FileCopyrightText: 2025 citron Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
@@ -31,6 +32,7 @@ protected:
void ReadUIGamelistValues() override; void ReadUIGamelistValues() override;
void ReadUILayoutValues() override; void ReadUILayoutValues() override;
void ReadMultiplayerValues() override; void ReadMultiplayerValues() override;
void ReadNetworkValues();
void SaveQtValues(); void SaveQtValues();
void SaveQtPlayerValues(std::size_t player_index); void SaveQtPlayerValues(std::size_t player_index);
@@ -43,6 +45,7 @@ protected:
void SaveUIGamelistValues() override; void SaveUIGamelistValues() override;
void SaveUILayoutValues() override; void SaveUILayoutValues() override;
void SaveMultiplayerValues() override; void SaveMultiplayerValues() override;
void SaveNetworkValues();
std::vector<Settings::BasicSetting*>& FindRelevantList(Settings::Category category) override; std::vector<Settings::BasicSetting*>& FindRelevantList(Settings::Category category) override;

View File

@@ -101,7 +101,7 @@ std::unique_ptr<Network::VerifyUser::Backend> HostRoomWindow::CreateVerifyBacken
if (use_validation) { if (use_validation) {
#ifdef ENABLE_WEB_SERVICE #ifdef ENABLE_WEB_SERVICE
verify_backend = verify_backend =
std::make_unique<WebService::VerifyUserJWT>(Settings::values.web_api_url.GetValue()); std::make_unique<WebService::VerifyUserJWT>(Settings::values.lobby_api_url.GetValue());
#else #else
verify_backend = std::make_unique<Network::VerifyUser::NullBackend>(); verify_backend = std::make_unique<Network::VerifyUser::NullBackend>();
#endif #endif
@@ -209,7 +209,7 @@ void HostRoomWindow::Host() {
std::string token; std::string token;
#ifdef ENABLE_WEB_SERVICE #ifdef ENABLE_WEB_SERVICE
if (is_public) { if (is_public) {
WebService::Client client(Settings::values.web_api_url.GetValue(), WebService::Client client(Settings::values.lobby_api_url.GetValue(),
Settings::values.citron_username.GetValue(), Settings::values.citron_username.GetValue(),
Settings::values.citron_token.GetValue()); Settings::values.citron_token.GetValue());
if (auto room = room_network.GetRoom().lock()) { if (auto room = room_network.GetRoom().lock()) {

View File

@@ -1,4 +1,5 @@
// SPDX-FileCopyrightText: Copyright 2017 Citra Emulator Project // SPDX-FileCopyrightText: Copyright 2017 Citra Emulator Project
// SPDX-FileCopyrightText: 2025 citron Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <QInputDialog> #include <QInputDialog>
@@ -189,7 +190,7 @@ void Lobby::OnJoinRoom(const QModelIndex& source) {
#ifdef ENABLE_WEB_SERVICE #ifdef ENABLE_WEB_SERVICE
if (!Settings::values.citron_username.GetValue().empty() && if (!Settings::values.citron_username.GetValue().empty() &&
!Settings::values.citron_token.GetValue().empty() && !verify_uid.empty()) { !Settings::values.citron_token.GetValue().empty() && !verify_uid.empty()) {
WebService::Client client(Settings::values.web_api_url.GetValue(), WebService::Client client(Settings::values.lobby_api_url.GetValue(),
Settings::values.citron_username.GetValue(), Settings::values.citron_username.GetValue(),
Settings::values.citron_token.GetValue()); Settings::values.citron_token.GetValue());
token = client.GetExternalJWT(verify_uid).returned_data; token = client.GetExternalJWT(verify_uid).returned_data;
@@ -396,14 +397,14 @@ bool LobbyFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex& s
for (int r = 0; r < game_list->rowCount(); ++r) { for (int r = 0; r < game_list->rowCount(); ++r) {
owned_games.append(QModelIndex(game_list->index(r, 0))); owned_games.append(QModelIndex(game_list->index(r, 0)));
} }
auto current_id = sourceModel()->data(game_name, LobbyItemGame::TitleIDRole).toLongLong(); auto current_id = sourceModel()->data(game_name, LobbyItemGame::TitleIDRole).toULongLong();
if (current_id == 0) { if (current_id == 0) {
// TODO(jroweboy): homebrew often doesn't have a game id and this hides them // TODO(jroweboy): homebrew often doesn't have a game id and this hides them
return false; return false;
} }
bool owned = false; bool owned = false;
for (const auto& game : owned_games) { for (const auto& game : owned_games) {
auto game_id = game_list->data(game, GameListItemPath::ProgramIdRole).toLongLong(); auto game_id = game_list->data(game, GameListItemPath::ProgramIdRole).toULongLong();
if (current_id == game_id) { if (current_id == game_id) {
owned = true; owned = true;
} }

View File

@@ -1,4 +1,5 @@
// SPDX-FileCopyrightText: Copyright 2017 Citra Emulator Project // SPDX-FileCopyrightText: Copyright 2017 Citra Emulator Project
// SPDX-FileCopyrightText: 2025 citron Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <chrono> #include <chrono>
@@ -22,7 +23,7 @@ static constexpr std::chrono::seconds announce_time_interval(15);
AnnounceMultiplayerSession::AnnounceMultiplayerSession(Network::RoomNetwork& room_network_) AnnounceMultiplayerSession::AnnounceMultiplayerSession(Network::RoomNetwork& room_network_)
: room_network{room_network_} { : room_network{room_network_} {
#ifdef ENABLE_WEB_SERVICE #ifdef ENABLE_WEB_SERVICE
backend = std::make_unique<WebService::RoomJson>(Settings::values.web_api_url.GetValue(), backend = std::make_unique<WebService::RoomJson>(Settings::values.lobby_api_url.GetValue(),
Settings::values.citron_username.GetValue(), Settings::values.citron_username.GetValue(),
Settings::values.citron_token.GetValue()); Settings::values.citron_token.GetValue());
#else #else
@@ -155,7 +156,7 @@ void AnnounceMultiplayerSession::UpdateCredentials() {
ASSERT_MSG(!IsRunning(), "Credentials can only be updated when session is not running"); ASSERT_MSG(!IsRunning(), "Credentials can only be updated when session is not running");
#ifdef ENABLE_WEB_SERVICE #ifdef ENABLE_WEB_SERVICE
backend = std::make_unique<WebService::RoomJson>(Settings::values.web_api_url.GetValue(), backend = std::make_unique<WebService::RoomJson>(Settings::values.lobby_api_url.GetValue(),
Settings::values.citron_username.GetValue(), Settings::values.citron_username.GetValue(),
Settings::values.citron_token.GetValue()); Settings::values.citron_token.GetValue());
#endif #endif