Move System Applets into a new category and deselect by default

As they are known to cause problems with Mii Maker and games like Tomodachi Life.
This commit is contained in:
zhupengfei
2020-11-28 15:39:59 +08:00
parent e238015e82
commit 2688a6ef61
4 changed files with 62 additions and 35 deletions
+5 -2
View File
@@ -84,6 +84,7 @@ bool SDMCImporter::ImportContent(const ContentSpecifier& specifier,
case ContentType::Sysdata: case ContentType::Sysdata:
return ImportSysdata(specifier.id, callback); return ImportSysdata(specifier.id, callback);
case ContentType::SystemTitle: case ContentType::SystemTitle:
case ContentType::SystemApplet:
return ImportNandTitle(specifier, callback); return ImportNandTitle(specifier, callback);
default: default:
UNREACHABLE(); UNREACHABLE();
@@ -720,9 +721,10 @@ void SDMCImporter::ListNandTitle(std::vector<ContentSpecifier>& out) const {
const auto& [name, extdata_id, encryption, seed_crypto, icon] = const auto& [name, extdata_id, encryption, seed_crypto, icon] =
LoadTitleData(ncch); LoadTitleData(ncch);
const auto type = (id >> 32) == 0x00040030 ? ContentType::SystemApplet
: ContentType::SystemTitle;
out.push_back( out.push_back(
{ContentType::SystemTitle, id, {type, id, FileUtil::Exists(citra_path + "content/"),
FileUtil::Exists(citra_path + "content/"),
FileUtil::GetDirectoryTreeSize(directory + virtual_name + "/content/"), FileUtil::GetDirectoryTreeSize(directory + virtual_name + "/content/"),
name, extdata_id, encryption, seed_crypto, icon}); name, extdata_id, encryption, seed_crypto, icon});
} while (false); } while (false);
@@ -883,6 +885,7 @@ void SDMCImporter::DeleteContent(const ContentSpecifier& specifier) {
case ContentType::Sysdata: case ContentType::Sysdata:
return DeleteSysdata(specifier.id); return DeleteSysdata(specifier.id);
case ContentType::SystemTitle: case ContentType::SystemTitle:
case ContentType::SystemApplet:
return DeleteNandTitle(specifier.id); return DeleteNandTitle(specifier.id);
default: default:
UNREACHABLE(); UNREACHABLE();
+10 -6
View File
@@ -28,6 +28,7 @@ enum class ContentType {
SystemArchive, SystemArchive,
Sysdata, Sysdata,
SystemTitle, SystemTitle,
SystemApplet, // This should belong to System Title, but they cause problems so a new category.
}; };
/** /**
@@ -110,8 +111,9 @@ public:
* Blocks, but can be aborted on another thread if needed. * Blocks, but can be aborted on another thread if needed.
* @return true on success, false otherwise * @return true on success, false otherwise
*/ */
bool ImportContent(const ContentSpecifier& specifier, bool ImportContent(
const ProgressCallback& callback = [](std::size_t, std::size_t) {}); const ContentSpecifier& specifier,
const ProgressCallback& callback = [](std::size_t, std::size_t) {});
/** /**
* Aborts current importing. * Aborts current importing.
@@ -123,8 +125,9 @@ public:
* Blocks, but can be aborted on another thread. * Blocks, but can be aborted on another thread.
* @return true on success, false otherwise * @return true on success, false otherwise
*/ */
bool DumpCXI(const ContentSpecifier& specifier, const std::string& destination, bool DumpCXI(
const ProgressCallback& callback = [](std::size_t, std::size_t) {}); const ContentSpecifier& specifier, const std::string& destination,
const ProgressCallback& callback = [](std::size_t, std::size_t) {});
/** /**
* Aborts current CXI dumping. * Aborts current CXI dumping.
@@ -136,8 +139,9 @@ public:
* Blocks, but can be aborted on another thread. * Blocks, but can be aborted on another thread.
* @return true on success, false otherwise * @return true on success, false otherwise
*/ */
bool BuildCIA(const ContentSpecifier& specifier, const std::string& destination, bool BuildCIA(
const ProgressCallback& callback = [](std::size_t, std::size_t) {}); const ContentSpecifier& specifier, const std::string& destination,
const ProgressCallback& callback = [](std::size_t, std::size_t) {});
/** /**
* Aborts current CIA building * Aborts current CIA building
+44 -26
View File
@@ -15,6 +15,7 @@
#include <QPushButton> #include <QPushButton>
#include <QStorageInfo> #include <QStorageInfo>
#include <QtConcurrent/QtConcurrentRun> #include <QtConcurrent/QtConcurrentRun>
#include "common/assert.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/scope_exit.h" #include "common/scope_exit.h"
#include "frontend/helpers/import_job.h" #include "frontend/helpers/import_job.h"
@@ -36,7 +37,7 @@ QString ReadableByteSize(qulonglong size) {
} }
// content type, name, icon name // content type, name, icon name
static constexpr std::array<std::tuple<Core::ContentType, const char*, const char*>, 8> static constexpr std::array<std::tuple<Core::ContentType, const char*, const char*>, 9>
ContentTypeMap{{ ContentTypeMap{{
{Core::ContentType::Application, QT_TR_NOOP("Application"), "app"}, {Core::ContentType::Application, QT_TR_NOOP("Application"), "app"},
{Core::ContentType::Update, QT_TR_NOOP("Update"), "update"}, {Core::ContentType::Update, QT_TR_NOOP("Update"), "update"},
@@ -46,6 +47,7 @@ static constexpr std::array<std::tuple<Core::ContentType, const char*, const cha
{Core::ContentType::SystemArchive, QT_TR_NOOP("System Archive"), "system_archive"}, {Core::ContentType::SystemArchive, QT_TR_NOOP("System Archive"), "system_archive"},
{Core::ContentType::Sysdata, QT_TR_NOOP("System Data"), "system_data"}, {Core::ContentType::Sysdata, QT_TR_NOOP("System Data"), "system_data"},
{Core::ContentType::SystemTitle, QT_TR_NOOP("System Title"), "hos"}, {Core::ContentType::SystemTitle, QT_TR_NOOP("System Title"), "hos"},
{Core::ContentType::SystemApplet, QT_TR_NOOP("System Applet"), "hos"},
}}; }};
static const std::unordered_map<Core::EncryptionType, const char*> EncryptionTypeMap{{ static const std::unordered_map<Core::EncryptionType, const char*> EncryptionTypeMap{{
@@ -144,7 +146,7 @@ void ImportDialog::RelistContent() {
RepopulateContent(); RepopulateContent();
}); });
auto future = QtConcurrent::run([& contents = this->contents, &importer = this->importer] { auto future = QtConcurrent::run([&contents = this->contents, &importer = this->importer] {
contents = importer.ListContent(); contents = importer.ListContent();
}); });
future_watcher->setFuture(future); future_watcher->setFuture(future);
@@ -192,6 +194,14 @@ void ImportDialog::InsertTopLevelItem(const QString& text, QPixmap icon) {
item->setFirstColumnSpanned(true); item->setFirstColumnSpanned(true);
} }
// Content types that themselves form a 'Title' like entity.
constexpr std::array<Core::ContentType, 4> SpecialContentTypeList{{
Core::ContentType::SystemArchive,
Core::ContentType::Sysdata,
Core::ContentType::SystemTitle,
Core::ContentType::SystemApplet,
}};
void ImportDialog::InsertSecondLevelItem(std::size_t row, const Core::ContentSpecifier& content, void ImportDialog::InsertSecondLevelItem(std::size_t row, const Core::ContentSpecifier& content,
std::size_t id, QString replace_name, std::size_t id, QString replace_name,
QPixmap replace_icon) { QPixmap replace_icon) {
@@ -208,7 +218,7 @@ void ImportDialog::InsertSecondLevelItem(std::size_t row, const Core::ContentSpe
name = QStringLiteral("%1 (%2)") name = QStringLiteral("%1 (%2)")
.arg(GetContentName(content)) .arg(GetContentName(content))
.arg(GetContentTypeName(content.type)); .arg(GetContentTypeName(content.type));
} else if (row <= 3) { } else if (row <= SpecialContentTypeList.size()) {
name = GetContentName(content); name = GetContentName(content);
} else { } else {
name = GetContentTypeName(content.type); name = GetContentTypeName(content.type);
@@ -228,7 +238,8 @@ void ImportDialog::InsertSecondLevelItem(std::size_t row, const Core::ContentSpe
if (content.type != Core::ContentType::Application && if (content.type != Core::ContentType::Application &&
content.type != Core::ContentType::Update && content.type != Core::ContentType::DLC && content.type != Core::ContentType::Update && content.type != Core::ContentType::DLC &&
content.type != Core::ContentType::SystemTitle) { content.type != Core::ContentType::SystemTitle &&
content.type != Core::ContentType::SystemApplet) {
// Do not display encryption in this case // Do not display encryption in this case
encryption.clear(); encryption.clear();
@@ -241,7 +252,8 @@ void ImportDialog::InsertSecondLevelItem(std::size_t row, const Core::ContentSpe
QPixmap icon; QPixmap icon;
if (replace_icon.isNull()) { if (replace_icon.isNull()) {
// Exclude system titles, they are a single group but have own icons. // Exclude system titles, they are a single group but have own icons.
if (use_title_view && content.type != Core::ContentType::SystemTitle) { if (use_title_view && content.type != Core::ContentType::SystemTitle &&
content.type != Core::ContentType::SystemApplet) {
icon = GetContentTypeIcon(content.type); icon = GetContentTypeIcon(content.type);
} else { } else {
// When not in title view, System Data and System Archive groups use category icons. // When not in title view, System Data and System Archive groups use category icons.
@@ -258,12 +270,21 @@ void ImportDialog::InsertSecondLevelItem(std::size_t row, const Core::ContentSpe
ui->main->setItemWidget(item, 0, checkBox); ui->main->setItemWidget(item, 0, checkBox);
connect(checkBox, &QCheckBox::stateChanged, connect(checkBox, &QCheckBox::stateChanged,
[this, item, size = content.maximum_size, type = content.type, [this, item, id = content.id, size = content.maximum_size, type = content.type,
exists = content.already_exists](int state) { exists = content.already_exists](int state) {
if (state == Qt::Checked) { if (state == Qt::Checked) {
if (!applet_warning_shown && !exists &&
type == Core::ContentType::SystemApplet) {
QMessageBox::warning(
this, tr("Warning"),
tr("You are trying to import System Applets.\nThese are known to cause "
"problems with certain games.\nOnly proceed if you understand what "
"you are doing."));
applet_warning_shown = true;
}
total_size += size; total_size += size;
} else { } else {
if (!warning_shown && !exists && if (!system_warning_shown && !exists &&
(type == Core::ContentType::SystemArchive || (type == Core::ContentType::SystemArchive ||
type == Core::ContentType::Sysdata || type == Core::ContentType::Sysdata ||
type == Core::ContentType::SystemTitle)) { type == Core::ContentType::SystemTitle)) {
@@ -273,7 +294,7 @@ void ImportDialog::InsertSecondLevelItem(std::size_t row, const Core::ContentSpe
tr("You are de-selecting important files that may be necessary for " tr("You are de-selecting important files that may be necessary for "
"your imported games to run.\nIt is highly recommended to import " "your imported games to run.\nIt is highly recommended to import "
"these contents if they do not exist yet.")); "these contents if they do not exist yet."));
warning_shown = true; system_warning_shown = true;
} }
total_size -= size; total_size -= size;
} }
@@ -284,7 +305,8 @@ void ImportDialog::InsertSecondLevelItem(std::size_t row, const Core::ContentSpe
} }
}); });
if (!content.already_exists) { // Skip System Applets, but enable everything else by default.
if (!content.already_exists && content.type != Core::ContentType::SystemApplet) {
checkBox->setChecked(true); checkBox->setChecked(true);
} }
} }
@@ -307,15 +329,15 @@ void ImportDialog::RepopulateContent() {
const bool use_title_view = ui->title_view_button->isChecked(); const bool use_title_view = ui->title_view_button->isChecked();
if (use_title_view) { if (use_title_view) {
// Create 'Ungrouped' category.
title_name_map.insert_or_assign(0, tr("Ungrouped")); title_name_map.insert_or_assign(0, tr("Ungrouped"));
title_name_map.insert_or_assign(1, tr("System Archive"));
title_name_map.insert_or_assign(2, tr("System Data"));
title_name_map.insert_or_assign(3, tr("System Title"));
title_icon_map.insert_or_assign(0, QIcon::fromTheme(QStringLiteral("unknown")).pixmap(24)); title_icon_map.insert_or_assign(0, QIcon::fromTheme(QStringLiteral("unknown")).pixmap(24));
title_icon_map.insert_or_assign(1, GetContentTypeIcon(Core::ContentType::SystemArchive));
title_icon_map.insert_or_assign(2, GetContentTypeIcon(Core::ContentType::Sysdata)); // Create categories for special content types.
title_icon_map.insert_or_assign(3, GetContentTypeIcon(Core::ContentType::SystemTitle)); for (std::size_t i = 0; i < SpecialContentTypeList.size(); ++i) {
title_name_map.insert_or_assign(i + 1, GetContentTypeName(SpecialContentTypeList[i]));
title_icon_map.insert_or_assign(i + 1, GetContentTypeIcon(SpecialContentTypeList[i]));
}
std::unordered_map<u64, u64> title_row_map; std::unordered_map<u64, u64> title_row_map;
for (const auto& [id, name] : title_name_map) { for (const auto& [id, name] : title_name_map) {
@@ -344,16 +366,12 @@ void ImportDialog::RepopulateContent() {
row = title_row_map.at(real_id); row = title_row_map.at(real_id);
break; break;
} }
case Core::ContentType::SystemArchive: { default: {
row = title_row_map.at(1); // System archive const std::size_t idx = std::find(SpecialContentTypeList.begin(),
break; SpecialContentTypeList.end(), content.type) -
} SpecialContentTypeList.begin();
case Core::ContentType::Sysdata: { ASSERT_MSG(idx < SpecialContentTypeList.size(), "Content Type not handled");
row = title_row_map.at(2); // System data row = title_row_map.at(idx + 1);
break;
}
case Core::ContentType::SystemTitle: {
row = title_row_map.at(3); // System title
break; break;
} }
} }
+3 -1
View File
@@ -64,7 +64,9 @@ private:
bool program_trigger = false; bool program_trigger = false;
// Whether the System Archive / System Data warning has been shown // Whether the System Archive / System Data warning has been shown
bool warning_shown = false; bool system_warning_shown = false;
// Whether the Applets warning has been shown
bool applet_warning_shown = false;
// TODO: Why this won't work as locals? // TODO: Why this won't work as locals?
Core::ContentSpecifier current_content = {}; Core::ContentSpecifier current_content = {};