Major revamps to match game loading decisions.
- Allow downloading titles from eshop and system settings - Remove encrypted game support
This commit is contained in:
@@ -507,8 +507,8 @@ void GMainWindow::InitializeWidgets() {
|
||||
emu_speed_label->setToolTip(tr("Current emulation speed. Values higher or lower than 100% "
|
||||
"indicate emulation is running faster or slower than a 3DS."));
|
||||
game_fps_label = new QLabel();
|
||||
game_fps_label->setToolTip(tr("How many frames per second the game is currently displaying. "
|
||||
"This will vary from game to game and scene to scene."));
|
||||
game_fps_label->setToolTip(tr("How many frames per second the app is currently displaying. "
|
||||
"This will vary from app to app and scene to scene."));
|
||||
emu_frametime_label = new QLabel();
|
||||
emu_frametime_label->setToolTip(
|
||||
tr("Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For "
|
||||
@@ -756,7 +756,7 @@ void GMainWindow::InitializeHotkeys() {
|
||||
link_action_shortcut(ui->action_Load_from_Newest_Slot, QStringLiteral("Load from Newest Slot"));
|
||||
link_action_shortcut(ui->action_Save_to_Oldest_Slot, QStringLiteral("Save to Oldest Slot"));
|
||||
link_action_shortcut(ui->action_View_Lobby,
|
||||
QStringLiteral("Multiplayer Browse Public Game Lobby"));
|
||||
QStringLiteral("Multiplayer Browse Public Application Lobby"));
|
||||
link_action_shortcut(ui->action_Start_Room, QStringLiteral("Multiplayer Create Room"));
|
||||
link_action_shortcut(ui->action_Connect_To_Room,
|
||||
QStringLiteral("Multiplayer Direct Connect to Room"));
|
||||
@@ -779,7 +779,7 @@ void GMainWindow::InitializeHotkeys() {
|
||||
ToggleFullscreen();
|
||||
}
|
||||
});
|
||||
connect_shortcut(QStringLiteral("Toggle Per-Game Speed"), [&] {
|
||||
connect_shortcut(QStringLiteral("Toggle Per-Application Speed"), [&] {
|
||||
Settings::values.frame_limit.SetGlobal(!Settings::values.frame_limit.UsingGlobal());
|
||||
UpdateStatusBar();
|
||||
});
|
||||
@@ -1164,7 +1164,7 @@ void GMainWindow::OnUpdateFound(bool found, bool error) {
|
||||
}
|
||||
|
||||
if (emulation_running && !explicit_update_check) {
|
||||
LOG_INFO(Frontend, "Update found, deferring as game is running");
|
||||
LOG_INFO(Frontend, "Update found, deferring as application is running");
|
||||
defer_update_prompt = true;
|
||||
return;
|
||||
}
|
||||
@@ -1223,7 +1223,7 @@ static std::optional<QDBusObjectPath> HoldWakeLockLinux(u32 window_id = 0) {
|
||||
//: TRANSLATORS: This string is shown to the user to explain why Citra needs to prevent the
|
||||
//: computer from sleeping
|
||||
options.insert(QString::fromLatin1("reason"),
|
||||
QCoreApplication::translate("GMainWindow", "Azahar is running a game"));
|
||||
QCoreApplication::translate("GMainWindow", "Azahar is running an application"));
|
||||
// 0x4: Suspend lock; 0x8: Idle lock
|
||||
QDBusReply<QDBusObjectPath> reply =
|
||||
xdp.call(QString::fromLatin1("Inhibit"),
|
||||
@@ -1295,8 +1295,8 @@ bool GMainWindow::LoadROM(const QString& filename) {
|
||||
case Core::System::ResultStatus::ErrorGetLoader:
|
||||
LOG_CRITICAL(Frontend, "Failed to obtain loader for {}!", filename.toStdString());
|
||||
QMessageBox::critical(
|
||||
this, tr("Invalid ROM Format"),
|
||||
tr("Your ROM format is not supported.<br/>Please follow the guides to redump your "
|
||||
this, tr("Invalid App Format"),
|
||||
tr("Your app format is not supported.<br/>Please follow the guides to redump your "
|
||||
"<a "
|
||||
"href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/"
|
||||
"dumping-game-cartridges/'>game "
|
||||
@@ -1308,10 +1308,10 @@ bool GMainWindow::LoadROM(const QString& filename) {
|
||||
break;
|
||||
|
||||
case Core::System::ResultStatus::ErrorSystemMode:
|
||||
LOG_CRITICAL(Frontend, "Failed to load ROM!");
|
||||
LOG_CRITICAL(Frontend, "Failed to load App!");
|
||||
QMessageBox::critical(
|
||||
this, tr("ROM Corrupted"),
|
||||
tr("Your ROM is corrupted. <br/>Please follow the guides to redump your "
|
||||
this, tr("App Corrupted"),
|
||||
tr("Your app is corrupted. <br/>Please follow the guides to redump your "
|
||||
"<a "
|
||||
"href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/"
|
||||
"dumping-game-cartridges/'>game "
|
||||
@@ -1323,23 +1323,17 @@ bool GMainWindow::LoadROM(const QString& filename) {
|
||||
break;
|
||||
|
||||
case Core::System::ResultStatus::ErrorLoader_ErrorEncrypted: {
|
||||
QMessageBox::critical(
|
||||
this, tr("ROM Encrypted"),
|
||||
tr("Your ROM is encrypted. <br/>Please follow the guides to redump your "
|
||||
"<a "
|
||||
"href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/"
|
||||
"dumping-game-cartridges/'>game "
|
||||
"cartridges</a> or "
|
||||
"<a "
|
||||
"href='https://web.archive.org/web/20240304210011/https://citra-emu.org/wiki/"
|
||||
"dumping-installed-titles/'>installed "
|
||||
"titles</a>."));
|
||||
QMessageBox::critical(this, tr("App Encrypted"),
|
||||
tr("Your app is encrypted. <br/>"
|
||||
"<a "
|
||||
"href='https://azahar-emu.org/blog/game-loading-changes/'>"
|
||||
"Please check our blog for more info.</a>"));
|
||||
break;
|
||||
}
|
||||
case Core::System::ResultStatus::ErrorLoader_ErrorInvalidFormat:
|
||||
QMessageBox::critical(
|
||||
this, tr("Invalid ROM Format"),
|
||||
tr("Your ROM format is not supported.<br/>Please follow the guides to redump your "
|
||||
this, tr("Invalid App Format"),
|
||||
tr("Your app format is not supported.<br/>Please follow the guides to redump your "
|
||||
"<a "
|
||||
"href='https://web.archive.org/web/20240304210021/https://citra-emu.org/wiki/"
|
||||
"dumping-game-cartridges/'>game "
|
||||
@@ -1351,8 +1345,8 @@ bool GMainWindow::LoadROM(const QString& filename) {
|
||||
break;
|
||||
|
||||
case Core::System::ResultStatus::ErrorLoader_ErrorGbaTitle:
|
||||
QMessageBox::critical(this, tr("Unsupported ROM"),
|
||||
tr("GBA Virtual Console ROMs are not supported by Azahar."));
|
||||
QMessageBox::critical(this, tr("Unsupported App"),
|
||||
tr("GBA Virtual Console is not supported by Azahar."));
|
||||
break;
|
||||
|
||||
case Core::System::ResultStatus::ErrorArticDisconnected:
|
||||
@@ -1365,7 +1359,7 @@ bool GMainWindow::LoadROM(const QString& filename) {
|
||||
break;
|
||||
default:
|
||||
QMessageBox::critical(
|
||||
this, tr("Error while loading ROM!"),
|
||||
this, tr("Error while loading App!"),
|
||||
tr("An unknown error occurred. Please see the log for more details."));
|
||||
break;
|
||||
}
|
||||
@@ -1430,7 +1424,7 @@ void GMainWindow::BootGame(const QString& filename) {
|
||||
const std::string name{is_artic ? "" : FileUtil::GetFilename(filename.toStdString())};
|
||||
const std::string config_file_name =
|
||||
title_id == 0 ? name : fmt::format("{:016X}", title_id);
|
||||
LOG_INFO(Frontend, "Loading per game config file for title {}", config_file_name);
|
||||
LOG_INFO(Frontend, "Loading per application config file for title {}", config_file_name);
|
||||
QtConfig per_game_config(config_file_name, QtConfig::ConfigType::PerGameConfig);
|
||||
}
|
||||
|
||||
@@ -1932,9 +1926,9 @@ bool GMainWindow::CreateShortcutMessagesGUI(QWidget* parent, int message,
|
||||
switch (message) {
|
||||
case GMainWindow::CREATE_SHORTCUT_MSGBOX_FULLSCREEN_PROMPT:
|
||||
buttons = QMessageBox::Yes | QMessageBox::No;
|
||||
result =
|
||||
QMessageBox::information(parent, tr("Create Shortcut"),
|
||||
tr("Do you want to launch the game in fullscreen?"), buttons);
|
||||
result = QMessageBox::information(
|
||||
parent, tr("Create Shortcut"),
|
||||
tr("Do you want to launch the application in fullscreen?"), buttons);
|
||||
return result == QMessageBox::Yes;
|
||||
case GMainWindow::CREATE_SHORTCUT_MSGBOX_SUCCESS:
|
||||
QMessageBox::information(parent, tr("Create Shortcut"),
|
||||
@@ -2147,7 +2141,7 @@ void GMainWindow::OnGameListAddDirectory() {
|
||||
UISettings::values.game_dirs.append(game_dir);
|
||||
game_list->PopulateAsync(UISettings::values.game_dirs);
|
||||
} else {
|
||||
LOG_WARNING(Frontend, "Selected directory is already in the game list");
|
||||
LOG_WARNING(Frontend, "Selected directory is already in the application list");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2164,7 +2158,7 @@ void GMainWindow::OnGameListOpenPerGameProperties(const QString& file) {
|
||||
u64 title_id{};
|
||||
if (!loader || loader->ReadProgramId(title_id) != Loader::ResultStatus::Success) {
|
||||
QMessageBox::information(this, tr("Properties"),
|
||||
tr("The game properties could not be loaded."));
|
||||
tr("The application properties could not be loaded."));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2260,10 +2254,11 @@ void GMainWindow::OnCIAInstallReport(Service::AM::InstallStatus status, QString
|
||||
QMessageBox::critical(this, tr("Invalid File"), tr("%1 is not a valid CIA").arg(filename));
|
||||
break;
|
||||
case Service::AM::InstallStatus::ErrorEncrypted:
|
||||
QMessageBox::critical(this, tr("Encrypted File"),
|
||||
tr("%1 must be decrypted "
|
||||
"before being used with Azahar. A real 3DS is required.")
|
||||
.arg(filename));
|
||||
QMessageBox::critical(this, tr("CIA Encrypted"),
|
||||
tr("Your CIA file is encrypted.<br/>"
|
||||
"<a "
|
||||
"href='https://azahar-emu.org/blog/game-loading-changes/'>"
|
||||
"Please check our blog for more info.</a>"));
|
||||
break;
|
||||
case Service::AM::InstallStatus::ErrorFileNotFound:
|
||||
QMessageBox::critical(this, tr("Unable to find File"),
|
||||
@@ -2625,9 +2620,10 @@ void GMainWindow::OnLoadState() {
|
||||
ASSERT(action);
|
||||
|
||||
if (UISettings::values.save_state_warning) {
|
||||
QMessageBox::warning(this, tr("Savestates"),
|
||||
tr("Warning: Savestates are NOT a replacement for in-game saves, "
|
||||
"and are not meant to be reliable.\n\nUse at your own risk!"));
|
||||
QMessageBox::warning(
|
||||
this, tr("Savestates"),
|
||||
tr("Warning: Savestates are NOT a replacement for in-application saves, "
|
||||
"and are not meant to be reliable.\n\nUse at your own risk!"));
|
||||
UISettings::values.save_state_warning = false;
|
||||
config->Save();
|
||||
}
|
||||
@@ -2709,7 +2705,7 @@ void GMainWindow::OnLoadAmiibo() {
|
||||
|
||||
if (!nfc->IsSearchingForAmiibos()) {
|
||||
QMessageBox::warning(this, tr("Error opening amiibo data file"),
|
||||
tr("Game is not looking for amiibos."));
|
||||
tr("Application is not looking for amiibos."));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2859,11 +2855,11 @@ void GMainWindow::OnCaptureScreenshot() {
|
||||
|
||||
const bool was_running = emu_thread->IsRunning();
|
||||
|
||||
if (was_running ||
|
||||
(QMessageBox::question(
|
||||
this, tr("Game will unpause"),
|
||||
tr("The game will be unpaused, and the next frame will be captured. Is this okay?"),
|
||||
QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes)) {
|
||||
if (was_running || (QMessageBox::question(this, tr("Application will unpause"),
|
||||
tr("The application will be unpaused, and the next "
|
||||
"frame will be captured. Is this okay?"),
|
||||
QMessageBox::Yes | QMessageBox::No,
|
||||
QMessageBox::No) == QMessageBox::Yes)) {
|
||||
if (was_running) {
|
||||
OnPauseGame();
|
||||
}
|
||||
@@ -3136,7 +3132,7 @@ void GMainWindow::UpdateStatusBar() {
|
||||
.arg(results.emulation_speed * 100.0, 0, 'f', 0)
|
||||
.arg(Settings::values.frame_limit.GetValue()));
|
||||
}
|
||||
game_fps_label->setText(tr("Game: %1 FPS").arg(results.game_fps, 0, 'f', 0));
|
||||
game_fps_label->setText(tr("App: %1 FPS").arg(results.game_fps, 0, 'f', 0));
|
||||
emu_frametime_label->setText(tr("Frame: %1 ms").arg(results.frametime * 1000.0, 0, 'f', 2));
|
||||
|
||||
if (show_artic_label) {
|
||||
@@ -3340,7 +3336,8 @@ void GMainWindow::OnCoreError(Core::System::ResultStatus result, std::string det
|
||||
if (can_continue) {
|
||||
message_box.addButton(tr("Continue"), QMessageBox::RejectRole);
|
||||
}
|
||||
QPushButton* abort_button = message_box.addButton(tr("Quit Game"), QMessageBox::AcceptRole);
|
||||
QPushButton* abort_button =
|
||||
message_box.addButton(tr("Quit Application"), QMessageBox::AcceptRole);
|
||||
if (result != Core::System::ResultStatus::ShutdownRequested)
|
||||
message_box.exec();
|
||||
|
||||
@@ -3470,7 +3467,7 @@ bool GMainWindow::ConfirmChangeGame() {
|
||||
}
|
||||
|
||||
auto answer = QMessageBox::question(
|
||||
this, tr("Azahar"), tr("The game is still running. Would you like to stop emulation?"),
|
||||
this, tr("Azahar"), tr("The application is still running. Would you like to stop emulation?"),
|
||||
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
|
||||
return answer != QMessageBox::No;
|
||||
}
|
||||
@@ -3675,8 +3672,8 @@ void GMainWindow::RetranslateStatusBar() {
|
||||
|
||||
emu_speed_label->setToolTip(tr("Current emulation speed. Values higher or lower than 100% "
|
||||
"indicate emulation is running faster or slower than a 3DS."));
|
||||
game_fps_label->setToolTip(tr("How many frames per second the game is currently displaying. "
|
||||
"This will vary from game to game and scene to scene."));
|
||||
game_fps_label->setToolTip(tr("How many frames per second the app is currently displaying. "
|
||||
"This will vary from app to app and scene to scene."));
|
||||
emu_frametime_label->setToolTip(
|
||||
tr("Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For "
|
||||
"full-speed emulation this should be at most 16.67 ms."));
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "core/hle/service/cfg/cfg.h"
|
||||
#include "core/hle/service/ptm/ptm.h"
|
||||
#include "core/hw/aes/key.h"
|
||||
#include "core/hw/unique_data.h"
|
||||
#include "core/system_titles.h"
|
||||
#include "ui_configure_system.h"
|
||||
|
||||
@@ -245,7 +246,7 @@ ConfigureSystem::ConfigureSystem(Core::System& system_, QWidget* parent)
|
||||
this, tr("Select SecureInfo_A/B"), QString(),
|
||||
tr("SecureInfo_A/B (SecureInfo_A SecureInfo_B);;All Files (*.*)"));
|
||||
ui->button_secure_info->setEnabled(true);
|
||||
InstallSecureData(file_path_qtstr.toStdString(), cfg->GetSecureInfoAPath());
|
||||
InstallSecureData(file_path_qtstr.toStdString(), HW::UniqueData::GetSecureInfoAPath());
|
||||
});
|
||||
connect(ui->button_friend_code_seed, &QPushButton::clicked, this, [this] {
|
||||
ui->button_friend_code_seed->setEnabled(false);
|
||||
@@ -254,14 +255,23 @@ ConfigureSystem::ConfigureSystem(Core::System& system_, QWidget* parent)
|
||||
tr("LocalFriendCodeSeed_A/B (LocalFriendCodeSeed_A "
|
||||
"LocalFriendCodeSeed_B);;All Files (*.*)"));
|
||||
ui->button_friend_code_seed->setEnabled(true);
|
||||
InstallSecureData(file_path_qtstr.toStdString(), cfg->GetLocalFriendCodeSeedBPath());
|
||||
InstallSecureData(file_path_qtstr.toStdString(),
|
||||
HW::UniqueData::GetLocalFriendCodeSeedBPath());
|
||||
});
|
||||
connect(ui->button_ct_cert, &QPushButton::clicked, this, [this] {
|
||||
ui->button_ct_cert->setEnabled(false);
|
||||
connect(ui->button_otp, &QPushButton::clicked, this, [this] {
|
||||
ui->button_otp->setEnabled(false);
|
||||
const QString file_path_qtstr =
|
||||
QFileDialog::getOpenFileName(this, tr("Select encrypted OTP file"), QString(),
|
||||
tr("Binary file (*.bin);;All Files (*.*)"));
|
||||
ui->button_otp->setEnabled(true);
|
||||
InstallSecureData(file_path_qtstr.toStdString(), HW::UniqueData::GetOTPPath());
|
||||
});
|
||||
connect(ui->button_movable, &QPushButton::clicked, this, [this] {
|
||||
ui->button_movable->setEnabled(false);
|
||||
const QString file_path_qtstr = QFileDialog::getOpenFileName(
|
||||
this, tr("Select CTCert"), QString(), tr("CTCert.bin (*.bin);;All Files (*.*)"));
|
||||
ui->button_ct_cert->setEnabled(true);
|
||||
InstallCTCert(file_path_qtstr.toStdString());
|
||||
this, tr("Select movable.sed"), QString(), tr("Sed file (*.sed);;All Files (*.*)"));
|
||||
ui->button_movable->setEnabled(true);
|
||||
InstallSecureData(file_path_qtstr.toStdString(), HW::UniqueData::GetMovablePath());
|
||||
});
|
||||
|
||||
for (u8 i = 0; i < country_names.size(); i++) {
|
||||
@@ -562,50 +572,39 @@ void ConfigureSystem::InstallSecureData(const std::string& from_path, const std:
|
||||
if (from.empty() || from == to) {
|
||||
return;
|
||||
}
|
||||
FileUtil::CreateFullPath(to_path);
|
||||
FileUtil::Copy(from, to);
|
||||
cfg->InvalidateSecureData();
|
||||
RefreshSecureDataStatus();
|
||||
}
|
||||
|
||||
void ConfigureSystem::InstallCTCert(const std::string& from_path) {
|
||||
std::string from =
|
||||
FileUtil::SanitizePath(from_path, FileUtil::DirectorySeparator::PlatformDefault);
|
||||
std::string to = FileUtil::SanitizePath(Service::AM::Module::GetCTCertPath(),
|
||||
FileUtil::DirectorySeparator::PlatformDefault);
|
||||
if (from.empty() || from == to) {
|
||||
return;
|
||||
}
|
||||
FileUtil::CreateFullPath(to);
|
||||
FileUtil::Copy(from, to);
|
||||
HW::UniqueData::InvalidateSecureData();
|
||||
RefreshSecureDataStatus();
|
||||
}
|
||||
|
||||
void ConfigureSystem::RefreshSecureDataStatus() {
|
||||
auto status_to_str = [](Service::CFG::SecureDataLoadStatus status) {
|
||||
auto status_to_str = [](HW::UniqueData::SecureDataLoadStatus status) {
|
||||
switch (status) {
|
||||
case Service::CFG::SecureDataLoadStatus::Loaded:
|
||||
case HW::UniqueData::SecureDataLoadStatus::Loaded:
|
||||
return "Loaded";
|
||||
case Service::CFG::SecureDataLoadStatus::NotFound:
|
||||
case HW::UniqueData::SecureDataLoadStatus::InvalidSignature:
|
||||
return "Loaded (Invalid Signature)";
|
||||
case HW::UniqueData::SecureDataLoadStatus::NotFound:
|
||||
return "Not Found";
|
||||
case Service::CFG::SecureDataLoadStatus::Invalid:
|
||||
case HW::UniqueData::SecureDataLoadStatus::Invalid:
|
||||
return "Invalid";
|
||||
case Service::CFG::SecureDataLoadStatus::IOError:
|
||||
case HW::UniqueData::SecureDataLoadStatus::IOError:
|
||||
return "IO Error";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
Service::AM::CTCert ct_cert;
|
||||
|
||||
ui->label_secure_info_status->setText(
|
||||
tr((std::string("Status: ") + status_to_str(cfg->LoadSecureInfoAFile())).c_str()));
|
||||
tr((std::string("Status: ") + status_to_str(HW::UniqueData::LoadSecureInfoA())).c_str()));
|
||||
ui->label_friend_code_seed_status->setText(
|
||||
tr((std::string("Status: ") + status_to_str(cfg->LoadLocalFriendCodeSeedBFile())).c_str()));
|
||||
ui->label_ct_cert_status->setText(
|
||||
tr((std::string("Status: ") + status_to_str(static_cast<Service::CFG::SecureDataLoadStatus>(
|
||||
Service::AM::Module::LoadCTCertFile(ct_cert))))
|
||||
tr((std::string("Status: ") + status_to_str(HW::UniqueData::LoadLocalFriendCodeSeedB()))
|
||||
.c_str()));
|
||||
ui->label_otp_status->setText(
|
||||
tr((std::string("Status: ") + status_to_str(HW::UniqueData::LoadOTP())).c_str()));
|
||||
ui->label_movable_status->setText(
|
||||
tr((std::string("Status: ") + status_to_str(HW::UniqueData::LoadMovable())).c_str()));
|
||||
}
|
||||
|
||||
void ConfigureSystem::RetranslateUI() {
|
||||
@@ -669,40 +668,7 @@ void ConfigureSystem::SetupPerGameUI() {
|
||||
void ConfigureSystem::DownloadFromNUS() {
|
||||
ui->button_start_download->setEnabled(false);
|
||||
|
||||
const auto mode =
|
||||
static_cast<Core::SystemTitleSet>(1 << ui->combo_download_set->currentIndex());
|
||||
const auto region = static_cast<u32>(ui->combo_download_region->currentIndex());
|
||||
const std::vector<u64> titles = Core::GetSystemTitleIds(mode, region);
|
||||
|
||||
QProgressDialog progress(tr("Downloading files..."), tr("Cancel"), 0,
|
||||
static_cast<int>(titles.size()), this);
|
||||
progress.setWindowModality(Qt::WindowModal);
|
||||
|
||||
QFutureWatcher<void> future_watcher;
|
||||
QObject::connect(&future_watcher, &QFutureWatcher<void>::finished, &progress,
|
||||
&QProgressDialog::reset);
|
||||
QObject::connect(&progress, &QProgressDialog::canceled, &future_watcher,
|
||||
&QFutureWatcher<void>::cancel);
|
||||
QObject::connect(&future_watcher, &QFutureWatcher<void>::progressValueChanged, &progress,
|
||||
&QProgressDialog::setValue);
|
||||
|
||||
auto failed = false;
|
||||
const auto download_title = [&future_watcher, &failed](const u64& title_id) {
|
||||
if (Service::AM::InstallFromNus(title_id) != Service::AM::InstallStatus::Success) {
|
||||
failed = true;
|
||||
future_watcher.cancel();
|
||||
}
|
||||
};
|
||||
|
||||
future_watcher.setFuture(QtConcurrent::map(titles, download_title));
|
||||
progress.exec();
|
||||
future_watcher.waitForFinished();
|
||||
|
||||
if (failed) {
|
||||
QMessageBox::critical(this, tr("Azahar"), tr("Downloading system files failed."));
|
||||
} else if (!future_watcher.isCanceled()) {
|
||||
QMessageBox::information(this, tr("Azahar"), tr("Successfully downloaded system files."));
|
||||
}
|
||||
QMessageBox::critical(this, tr("Azahar"), tr("Downloading from NUS has been deprecated."));
|
||||
|
||||
ui->button_start_download->setEnabled(true);
|
||||
}
|
||||
|
||||
@@ -53,7 +53,6 @@ private:
|
||||
void RefreshConsoleID();
|
||||
|
||||
void InstallSecureData(const std::string& from_path, const std::string& to_path);
|
||||
void InstallCTCert(const std::string& from_path);
|
||||
void RefreshSecureDataStatus();
|
||||
|
||||
void SetupPerGameUI();
|
||||
|
||||
@@ -629,24 +629,60 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_ct_cert">
|
||||
<widget class="QLabel" name="label_otp">
|
||||
<property name="text">
|
||||
<string>CTCert</string>
|
||||
<string>OTP</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QWidget" name="ct_cert">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_ct_cert">
|
||||
<widget class="QWidget" name="otp">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_otp">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_ct_cert_status">
|
||||
<widget class="QLabel" name="label_otp_status">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="button_ct_cert">
|
||||
<widget class="QPushButton" name="button_otp">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="layoutDirection">
|
||||
<enum>Qt::RightToLeft</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Choose</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_movable">
|
||||
<property name="text">
|
||||
<string>movable.sed</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QWidget" name="otp">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_movable">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_movable_status">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="button_movable">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
|
||||
@@ -596,7 +596,7 @@ void GameList::AddGamePopup(QMenu& context_menu, const QString& path, const QStr
|
||||
QMenu* uninstall_menu = context_menu.addMenu(tr("Uninstall"));
|
||||
QAction* uninstall_all = uninstall_menu->addAction(tr("Everything"));
|
||||
uninstall_menu->addSeparator();
|
||||
QAction* uninstall_game = uninstall_menu->addAction(tr("Game"));
|
||||
QAction* uninstall_game = uninstall_menu->addAction(tr("Application"));
|
||||
QAction* uninstall_update = uninstall_menu->addAction(tr("Update"));
|
||||
QAction* uninstall_dlc = uninstall_menu->addAction(tr("DLC"));
|
||||
|
||||
@@ -736,7 +736,7 @@ void GameList::AddGamePopup(QMenu& context_menu, const QString& path, const QStr
|
||||
QMessageBox::StandardButton answer = QMessageBox::question(
|
||||
this, tr("Azahar"),
|
||||
tr("Are you sure you want to completely uninstall '%1'?\n\nThis will "
|
||||
"delete the game if installed, as well as any installed updates or DLC.")
|
||||
"delete the application if installed, as well as any installed updates or DLC.")
|
||||
.arg(name),
|
||||
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
|
||||
if (answer == QMessageBox::Yes) {
|
||||
@@ -805,7 +805,7 @@ void GameList::AddCustomDirPopup(QMenu& context_menu, QModelIndex selected) {
|
||||
UISettings::values.game_dirs[selected.data(GameListDir::GameDirRole).toInt()];
|
||||
|
||||
QAction* deep_scan = context_menu.addAction(tr("Scan Subfolders"));
|
||||
QAction* delete_dir = context_menu.addAction(tr("Remove Game Directory"));
|
||||
QAction* delete_dir = context_menu.addAction(tr("Remove Application Directory"));
|
||||
|
||||
deep_scan->setCheckable(true);
|
||||
deep_scan->setChecked(game_dir.deep_scan);
|
||||
@@ -885,18 +885,18 @@ void GameList::LoadCompatibilityList() {
|
||||
QFile compat_list{QStringLiteral(":compatibility_list/compatibility_list.json")};
|
||||
|
||||
if (!compat_list.open(QFile::ReadOnly | QFile::Text)) {
|
||||
LOG_ERROR(Frontend, "Unable to open game compatibility list");
|
||||
LOG_ERROR(Frontend, "Unable to open application compatibility list");
|
||||
return;
|
||||
}
|
||||
|
||||
if (compat_list.size() == 0) {
|
||||
LOG_WARNING(Frontend, "Game compatibility list is empty");
|
||||
LOG_WARNING(Frontend, "Application compatibility list is empty");
|
||||
return;
|
||||
}
|
||||
|
||||
const QByteArray content = compat_list.readAll();
|
||||
if (content.isEmpty()) {
|
||||
LOG_ERROR(Frontend, "Unable to completely read game compatibility list");
|
||||
LOG_ERROR(Frontend, "Unable to completely read application compatibility list");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1004,12 +1004,12 @@ void GameList::LoadInterfaceLayout() {
|
||||
}
|
||||
|
||||
const QStringList GameList::supported_file_extensions = {
|
||||
QStringLiteral("3ds"), QStringLiteral("3dsx"), QStringLiteral("elf"), QStringLiteral("axf"),
|
||||
QStringLiteral("cci"), QStringLiteral("cxi"), QStringLiteral("app")};
|
||||
QStringLiteral("3dsx"), QStringLiteral("elf"), QStringLiteral("axf"),
|
||||
QStringLiteral("cci"), QStringLiteral("cxi"), QStringLiteral("app")};
|
||||
|
||||
void GameList::RefreshGameDirectory() {
|
||||
if (!UISettings::values.game_dirs.isEmpty() && current_worker != nullptr) {
|
||||
LOG_INFO(Frontend, "Change detected in the games directory. Reloading game list.");
|
||||
LOG_INFO(Frontend, "Change detected in the applications directory. Reloading game list.");
|
||||
PopulateAsync(UISettings::values.game_dirs);
|
||||
}
|
||||
}
|
||||
@@ -1094,7 +1094,7 @@ GameListPlaceholder::GameListPlaceholder(GMainWindow* parent) : QWidget{parent}
|
||||
layout->setAlignment(Qt::AlignCenter);
|
||||
image->setPixmap(QIcon::fromTheme(QStringLiteral("plus_folder")).pixmap(200));
|
||||
|
||||
text->setText(tr("Double-click to add a new folder to the game list"));
|
||||
text->setText(tr("Double-click to add a new folder to the application list"));
|
||||
QFont font = text->font();
|
||||
font.setPointSize(20);
|
||||
text->setFont(font);
|
||||
|
||||
@@ -163,7 +163,7 @@ public:
|
||||
|
||||
GameListItemPath() = default;
|
||||
GameListItemPath(const QString& game_path, std::span<const u8> smdh_data, u64 program_id,
|
||||
u64 extdata_id, Service::FS::MediaType media_type) {
|
||||
u64 extdata_id, Service::FS::MediaType media_type, bool is_encrypted) {
|
||||
setData(type(), TypeRole);
|
||||
setData(game_path, FullPathRole);
|
||||
setData(qulonglong(program_id), ProgramIdRole);
|
||||
@@ -184,6 +184,9 @@ public:
|
||||
if (UISettings::values.game_list_icon_size.GetValue() !=
|
||||
UISettings::GameListIconSize::NoIcon)
|
||||
setData(GetDefaultIcon(large), Qt::DecorationRole);
|
||||
if (is_encrypted) {
|
||||
setData(QObject::tr("Unsupported encrypted application"), TitleRole);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -262,13 +265,13 @@ public:
|
||||
};
|
||||
// clang-format off
|
||||
static const std::map<QString, CompatStatus> status_data = {
|
||||
{QStringLiteral("0"), {QStringLiteral("#5c93ed"), QT_TR_NOOP("Perfect"), QT_TR_NOOP("Game functions flawless with no audio or graphical glitches, all tested functionality works as intended without\nany workarounds needed.")}},
|
||||
{QStringLiteral("1"), {QStringLiteral("#47d35c"), QT_TR_NOOP("Great"), QT_TR_NOOP("Game functions with minor graphical or audio glitches and is playable from start to finish. May require some\nworkarounds.")}},
|
||||
{QStringLiteral("2"), {QStringLiteral("#94b242"), QT_TR_NOOP("Okay"), QT_TR_NOOP("Game functions with major graphical or audio glitches, but game is playable from start to finish with\nworkarounds.")}},
|
||||
{QStringLiteral("3"), {QStringLiteral("#f2d624"), QT_TR_NOOP("Bad"), QT_TR_NOOP("Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches\neven with workarounds.")}},
|
||||
{QStringLiteral("4"), {QStringLiteral("#ff0000"), QT_TR_NOOP("Intro/Menu"), QT_TR_NOOP("Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start\nScreen.")}},
|
||||
{QStringLiteral("5"), {QStringLiteral("#828282"), QT_TR_NOOP("Won't Boot"), QT_TR_NOOP("The game crashes when attempting to startup.")}},
|
||||
{QStringLiteral("99"), {QStringLiteral("#000000"), QT_TR_NOOP("Not Tested"), QT_TR_NOOP("The game has not yet been tested.")}}};
|
||||
{QStringLiteral("0"), {QStringLiteral("#5c93ed"), QT_TR_NOOP("Perfect"), QT_TR_NOOP("App functions flawless with no audio or graphical glitches, all tested functionality works as intended without\nany workarounds needed.")}},
|
||||
{QStringLiteral("1"), {QStringLiteral("#47d35c"), QT_TR_NOOP("Great"), QT_TR_NOOP("App functions with minor graphical or audio glitches and is playable from start to finish. May require some\nworkarounds.")}},
|
||||
{QStringLiteral("2"), {QStringLiteral("#94b242"), QT_TR_NOOP("Okay"), QT_TR_NOOP("App functions with major graphical or audio glitches, but app is playable from start to finish with\nworkarounds.")}},
|
||||
{QStringLiteral("3"), {QStringLiteral("#f2d624"), QT_TR_NOOP("Bad"), QT_TR_NOOP("App functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches\neven with workarounds.")}},
|
||||
{QStringLiteral("4"), {QStringLiteral("#ff0000"), QT_TR_NOOP("Intro/Menu"), QT_TR_NOOP("App is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start\nScreen.")}},
|
||||
{QStringLiteral("5"), {QStringLiteral("#828282"), QT_TR_NOOP("Won't Boot"), QT_TR_NOOP("The app crashes when attempting to startup.")}},
|
||||
{QStringLiteral("99"), {QStringLiteral("#000000"), QT_TR_NOOP("Not Tested"), QT_TR_NOOP("The app has not yet been tested.")}}};
|
||||
// clang-format on
|
||||
|
||||
auto iterator = status_data.find(compatibility);
|
||||
@@ -445,7 +448,7 @@ public:
|
||||
|
||||
int icon_size = IconSizes.at(UISettings::values.game_list_icon_size.GetValue());
|
||||
setData(QIcon::fromTheme(QStringLiteral("plus")).pixmap(icon_size), Qt::DecorationRole);
|
||||
setData(QObject::tr("Add New Game Directory"), Qt::DisplayRole);
|
||||
setData(QObject::tr("Add New Application Directory"), Qt::DisplayRole);
|
||||
}
|
||||
|
||||
int type() const override {
|
||||
|
||||
@@ -108,7 +108,8 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign
|
||||
emit EntryReady(
|
||||
{
|
||||
new GameListItemPath(QString::fromStdString(physical_name), smdh, program_id,
|
||||
extdata_id, media_type),
|
||||
extdata_id, media_type,
|
||||
res == Loader::ResultStatus::ErrorEncrypted),
|
||||
new GameListItemCompat(compatibility),
|
||||
new GameListItemRegion(smdh),
|
||||
new GameListItem(
|
||||
|
||||
@@ -446,7 +446,7 @@
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Browse Public Game Lobby</string>
|
||||
<string>Browse Public Application Lobby</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_Start_Room">
|
||||
@@ -688,7 +688,7 @@
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Configure Current Game...</string>
|
||||
<string>Configure Current Application...</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::NoRole</enum>
|
||||
|
||||
Reference in New Issue
Block a user