[desktop] Initial data manager prototype
Right now, all this adds is a small dialog to the Widgets frontend showing the user how much space is taken up by their saves, shaders, NAND, and mods. It also gives them the choice to clear these directories (with 2x confirmation), OR open the directory in their system file manager. In the future, a lot more can be done with this concept. Notably, a common import/export (a la android) could be added, the UI can obviously be polished, etc. We could also add this to Android, but I don't think common import/export is needed *for* Android, and should probably be left in qt_common. Signed-off-by: crueter <crueter@eden-emu.dev>
This commit is contained in:
parent
3c6ef765af
commit
f6908bba1e
15 changed files with 478 additions and 7 deletions
|
@ -7,6 +7,7 @@ add_library(frontend_common STATIC
|
|||
content_manager.h
|
||||
firmware_manager.h
|
||||
firmware_manager.cpp
|
||||
data_manager.h data_manager.cpp
|
||||
)
|
||||
|
||||
create_target_directory_groups(frontend_common)
|
||||
|
|
72
src/frontend_common/data_manager.cpp
Normal file
72
src/frontend_common/data_manager.cpp
Normal file
|
@ -0,0 +1,72 @@
|
|||
#include "data_manager.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/fs/path_util.h"
|
||||
#include <filesystem>
|
||||
#include <fmt/format.h>
|
||||
|
||||
namespace FrontendCommon::DataManager {
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
const std::string GetDataDir(DataDir dir)
|
||||
{
|
||||
const fs::path nand_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir);
|
||||
|
||||
switch (dir) {
|
||||
case DataDir::Saves:
|
||||
return (nand_dir / "user" / "save" / "0000000000000000").string();
|
||||
case DataDir::UserNand:
|
||||
return (nand_dir / "user" / "Contents" / "registered").string();
|
||||
case DataDir::SysNand:
|
||||
return (nand_dir / "system").string();
|
||||
case DataDir::Mods:
|
||||
return Common::FS::GetEdenPathString(Common::FS::EdenPath::LoadDir);
|
||||
case DataDir::Shaders:
|
||||
return Common::FS::GetEdenPathString(Common::FS::EdenPath::ShaderDir);
|
||||
default:
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
u64 ClearDir(DataDir dir)
|
||||
{
|
||||
fs::path data_dir = GetDataDir(dir);
|
||||
u64 result = fs::remove_all(data_dir);
|
||||
|
||||
// mkpath at the end just so it actually exists
|
||||
fs::create_directories(data_dir);
|
||||
return result;
|
||||
}
|
||||
|
||||
const std::string ReadableBytesSize(u64 size)
|
||||
{
|
||||
static constexpr std::array units{"B", "KiB", "MiB", "GiB", "TiB", "PiB"};
|
||||
if (size == 0) {
|
||||
return "0 B";
|
||||
}
|
||||
|
||||
const int digit_groups = (std::min) (static_cast<int>(std::log10(size) / std::log10(1024)),
|
||||
static_cast<int>(units.size()));
|
||||
return fmt::format("{:.1f} {}", size / std::pow(1024, digit_groups), units[digit_groups]);
|
||||
}
|
||||
|
||||
u64 DataDirSize(DataDir dir)
|
||||
{
|
||||
fs::path data_dir = GetDataDir(dir);
|
||||
u64 size = 0;
|
||||
|
||||
if (!fs::exists(data_dir))
|
||||
return 0;
|
||||
|
||||
for (const auto& entry : fs::recursive_directory_iterator(data_dir)) {
|
||||
if (!entry.is_directory()) {
|
||||
size += entry.file_size();
|
||||
}
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
}
|
21
src/frontend_common/data_manager.h
Normal file
21
src/frontend_common/data_manager.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
#ifndef DATA_MANAGER_H
|
||||
#define DATA_MANAGER_H
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include <string>
|
||||
|
||||
namespace FrontendCommon::DataManager {
|
||||
|
||||
enum class DataDir { Saves, UserNand, SysNand, Mods, Shaders };
|
||||
|
||||
const std::string GetDataDir(DataDir dir);
|
||||
|
||||
u64 ClearDir(DataDir dir);
|
||||
|
||||
const std::string ReadableBytesSize(u64 size);
|
||||
|
||||
u64 DataDirSize(DataDir dir);
|
||||
|
||||
}; // namespace FrontendCommon::DataManager
|
||||
|
||||
#endif // DATA_MANAGER_H
|
|
@ -4,9 +4,6 @@
|
|||
# SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core)
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core)
|
||||
|
||||
add_library(qt_common STATIC
|
||||
qt_common.h
|
||||
qt_common.cpp
|
||||
|
@ -27,6 +24,7 @@ add_library(qt_common STATIC
|
|||
qt_rom_util.h qt_rom_util.cpp
|
||||
qt_applet_util.h qt_applet_util.cpp
|
||||
qt_progress_dialog.h qt_progress_dialog.cpp
|
||||
qt_string_lookup.h
|
||||
|
||||
)
|
||||
|
||||
|
@ -40,6 +38,7 @@ endif()
|
|||
add_subdirectory(externals)
|
||||
|
||||
target_link_libraries(qt_common PRIVATE core Qt6::Core SimpleIni::SimpleIni QuaZip::QuaZip)
|
||||
target_link_libraries(qt_common PUBLIC frozen::frozen)
|
||||
|
||||
if (NOT APPLE AND ENABLE_OPENGL)
|
||||
target_compile_definitions(qt_common PUBLIC HAS_OPENGL)
|
||||
|
|
2
src/qt_common/externals/CMakeLists.txt
vendored
2
src/qt_common/externals/CMakeLists.txt
vendored
|
@ -17,4 +17,4 @@ AddJsonPackage(quazip)
|
|||
|
||||
# frozen
|
||||
# TODO(crueter): Qt String Lookup
|
||||
# AddJsonPackage(frozen)
|
||||
AddJsonPackage(frozen)
|
||||
|
|
|
@ -348,4 +348,29 @@ void FixProfiles()
|
|||
QtCommon::Game::OpenSaveFolder();
|
||||
}
|
||||
|
||||
void ClearDataDir(FrontendCommon::DataManager::DataDir dir) {
|
||||
auto result = QtCommon::Frontend::Warning("Really clear data?",
|
||||
"Important data may be lost!",
|
||||
QMessageBox::Yes | QMessageBox::No);
|
||||
|
||||
if (result != QMessageBox::Yes)
|
||||
return;
|
||||
|
||||
result = QtCommon::Frontend::Warning(
|
||||
"Are you REALLY sure?",
|
||||
"Once deleted, your data will NOT come back!\n"
|
||||
"Only do this if you're 100% sure you want to delete this data.",
|
||||
QMessageBox::Yes | QMessageBox::No);
|
||||
|
||||
if (result != QMessageBox::Yes)
|
||||
return;
|
||||
|
||||
QtCommon::Frontend::QtProgressDialog dialog(tr("Clearing..."), QString(), 0, 0);
|
||||
dialog.show();
|
||||
|
||||
FrontendCommon::DataManager::ClearDir(dir);
|
||||
|
||||
dialog.close();
|
||||
}
|
||||
|
||||
} // namespace QtCommon::Content
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include <QObject>
|
||||
#include "common/common_types.h"
|
||||
#include "frontend_common/data_manager.h"
|
||||
|
||||
namespace QtCommon::Content {
|
||||
|
||||
|
@ -46,6 +47,8 @@ void InstallKeys();
|
|||
void VerifyGameContents(const std::string &game_path);
|
||||
void VerifyInstalledContents();
|
||||
|
||||
void ClearDataDir(FrontendCommon::DataManager::DataDir dir);
|
||||
|
||||
// Profiles //
|
||||
void FixProfiles();
|
||||
}
|
||||
|
|
35
src/qt_common/qt_string_lookup.h
Normal file
35
src/qt_common/qt_string_lookup.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
#include <frozen/string.h>
|
||||
#include <frozen/unordered_map.h>
|
||||
#include <qobjectdefs.h>
|
||||
#include <qtmetamacros.h>
|
||||
|
||||
namespace QtCommon::StringLookup {
|
||||
|
||||
Q_NAMESPACE
|
||||
|
||||
// TODO(crueter): QML interface
|
||||
enum StringKey {
|
||||
SavesTooltip,
|
||||
ShadersTooltip,
|
||||
UserNandTooltip,
|
||||
SysNandTooltip,
|
||||
ModsTooltip,
|
||||
};
|
||||
|
||||
static constexpr const frozen::unordered_map<StringKey, frozen::string, 5> strings = {
|
||||
{SavesTooltip, "DO NOT REMOVE UNLESS YOU KNOW WHAT YOU'RE DOING!"},
|
||||
{ShadersTooltip, "Shader pipeline caches. Generally safe to remove."},
|
||||
{UserNandTooltip, "Contains updates and DLC for games."},
|
||||
{SysNandTooltip, "Contains firmware and applet data."},
|
||||
{ModsTooltip, "Contains all of your mod data."},
|
||||
};
|
||||
|
||||
static inline const QString Lookup(StringKey key)
|
||||
{
|
||||
return QString::fromStdString(strings.at(key).data());
|
||||
}
|
||||
|
||||
}
|
|
@ -234,6 +234,8 @@ add_executable(yuzu
|
|||
deps_dialog.cpp
|
||||
deps_dialog.h
|
||||
deps_dialog.ui
|
||||
|
||||
data_dialog.h data_dialog.cpp data_dialog.ui
|
||||
)
|
||||
|
||||
set_target_properties(yuzu PROPERTIES OUTPUT_NAME "eden")
|
||||
|
|
104
src/yuzu/data_dialog.cpp
Normal file
104
src/yuzu/data_dialog.cpp
Normal file
|
@ -0,0 +1,104 @@
|
|||
#include "data_dialog.h"
|
||||
#include "frontend_common/data_manager.h"
|
||||
#include "qt_common/qt_content_util.h"
|
||||
#include "qt_common/qt_frontend_util.h"
|
||||
#include "qt_common/qt_progress_dialog.h"
|
||||
#include "qt_common/qt_string_lookup.h"
|
||||
#include "ui_data_dialog.h"
|
||||
|
||||
#include <QDesktopServices>
|
||||
#include <QFutureWatcher>
|
||||
#include <QMenu>
|
||||
#include <QProgressDialog>
|
||||
#include <QtConcurrent/qtconcurrentrun.h>
|
||||
#include <qnamespace.h>
|
||||
|
||||
DataDialog::DataDialog(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, ui(std::make_unique<Ui::DataDialog>())
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
std::size_t row = 0;
|
||||
#define TABLE_ITEM(label, name, data_dir) \
|
||||
QTableWidgetItem *name##Label = new QTableWidgetItem(tr(label)); \
|
||||
name##Label->setToolTip( \
|
||||
QtCommon::StringLookup::Lookup(QtCommon::StringLookup::data_dir##Tooltip)); \
|
||||
ui->sizes->setItem(row, 0, name##Label); \
|
||||
DataItem *name##Item = new DataItem(FrontendCommon::DataManager::DataDir::data_dir, this); \
|
||||
ui->sizes->setItem(row, 1, name##Item); \
|
||||
++row;
|
||||
|
||||
TABLE_ITEM("Saves", save, Saves)
|
||||
TABLE_ITEM("Shaders", shaders, Shaders)
|
||||
TABLE_ITEM("UserNAND", user, UserNand)
|
||||
TABLE_ITEM("SysNAND", sys, SysNand)
|
||||
TABLE_ITEM("Mods", mods, Mods)
|
||||
|
||||
#undef TABLE_ITEM
|
||||
|
||||
QObject::connect(ui->sizes, &QTableWidget::customContextMenuRequested, this, [this]() {
|
||||
auto items = ui->sizes->selectedItems();
|
||||
if (items.empty())
|
||||
return;
|
||||
|
||||
QTableWidgetItem *selected = items.at(0);
|
||||
DataItem *item = (DataItem *) ui->sizes->item(selected->row(), 1);
|
||||
|
||||
QMenu *menu = new QMenu(this);
|
||||
QAction *open = menu->addAction(tr("Open"));
|
||||
QObject::connect(open, &QAction::triggered, this, [item]() {
|
||||
auto data_dir
|
||||
= item->data(DataItem::DATA_DIR).value<FrontendCommon::DataManager::DataDir>();
|
||||
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(
|
||||
QString::fromStdString(FrontendCommon::DataManager::GetDataDir(data_dir))));
|
||||
});
|
||||
|
||||
QAction *clear = menu->addAction(tr("Clear"));
|
||||
QObject::connect(clear, &QAction::triggered, this, [item]() {
|
||||
auto data_dir
|
||||
= item->data(DataItem::DATA_DIR).value<FrontendCommon::DataManager::DataDir>();
|
||||
|
||||
QtCommon::Content::ClearDataDir(data_dir);
|
||||
|
||||
item->scan();
|
||||
});
|
||||
|
||||
menu->exec(QCursor::pos());
|
||||
});
|
||||
}
|
||||
|
||||
DataDialog::~DataDialog() = default;
|
||||
|
||||
DataItem::DataItem(FrontendCommon::DataManager::DataDir data_dir, QWidget *parent)
|
||||
: QTableWidgetItem(QObject::tr("Calculating"))
|
||||
, m_parent(parent)
|
||||
, m_dir(data_dir)
|
||||
{
|
||||
setData(DataItem::DATA_DIR, QVariant::fromValue(m_dir));
|
||||
scan();
|
||||
}
|
||||
|
||||
bool DataItem::operator<(const QTableWidgetItem &other) const
|
||||
{
|
||||
return this->data(DataRole::SIZE).toULongLong() < other.data(DataRole::SIZE).toULongLong();
|
||||
}
|
||||
|
||||
void DataItem::reset() {
|
||||
setText(QStringLiteral("0 B"));
|
||||
setData(DataItem::SIZE, QVariant::fromValue(0ULL));
|
||||
}
|
||||
|
||||
void DataItem::scan() {
|
||||
m_watcher = new QFutureWatcher<u64>(m_parent);
|
||||
|
||||
m_parent->connect(m_watcher, &QFutureWatcher<u64>::finished, m_parent, [=, this]() {
|
||||
u64 size = m_watcher->result();
|
||||
setText(QString::fromStdString(FrontendCommon::DataManager::ReadableBytesSize(size)));
|
||||
setData(DataItem::SIZE, QVariant::fromValue(size));
|
||||
});
|
||||
|
||||
m_watcher->setFuture(
|
||||
QtConcurrent::run([this]() { return FrontendCommon::DataManager::DataDirSize(m_dir); }));
|
||||
}
|
43
src/yuzu/data_dialog.h
Normal file
43
src/yuzu/data_dialog.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
#ifndef DATA_DIALOG_H
|
||||
#define DATA_DIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QFutureWatcher>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QTableWidgetItem>
|
||||
#include "frontend_common/data_manager.h"
|
||||
#include <qnamespace.h>
|
||||
|
||||
namespace Ui {
|
||||
class DataDialog;
|
||||
}
|
||||
|
||||
class DataDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DataDialog(QWidget *parent = nullptr);
|
||||
~DataDialog();
|
||||
|
||||
private:
|
||||
std::unique_ptr<Ui::DataDialog> ui;
|
||||
};
|
||||
|
||||
class DataItem : public QTableWidgetItem
|
||||
{
|
||||
public:
|
||||
DataItem(FrontendCommon::DataManager::DataDir data_dir, QWidget *parent);
|
||||
enum DataRole { SIZE = Qt::UserRole + 1, DATA_DIR };
|
||||
|
||||
bool operator<(const QTableWidgetItem &other) const;
|
||||
void reset();
|
||||
void scan();
|
||||
|
||||
private:
|
||||
QWidget *m_parent;
|
||||
QFutureWatcher<u64> *m_watcher = nullptr;
|
||||
FrontendCommon::DataManager::DataDir m_dir;
|
||||
};
|
||||
|
||||
#endif // DATA_DIALOG_H
|
152
src/yuzu/data_dialog.ui
Normal file
152
src/yuzu/data_dialog.ui
Normal file
|
@ -0,0 +1,152 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>DataDialog</class>
|
||||
<widget class="QDialog" name="DataDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>300</width>
|
||||
<height>350</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>300</width>
|
||||
<height>320</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Data Manager</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Right-click on an item to either open it or clear it. Hold your mouse over an item to see more information about it.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTableWidget" name="sizes">
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::ContextMenuPolicy::CustomContextMenu</enum>
|
||||
</property>
|
||||
<property name="editTriggers">
|
||||
<set>QAbstractItemView::EditTrigger::NoEditTriggers</set>
|
||||
</property>
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::SelectionMode::SingleSelection</enum>
|
||||
</property>
|
||||
<property name="sortingEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="cornerButtonEnabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<attribute name="horizontalHeaderMinimumSectionSize">
|
||||
<number>80</number>
|
||||
</attribute>
|
||||
<attribute name="horizontalHeaderStretchLastSection">
|
||||
<bool>true</bool>
|
||||
</attribute>
|
||||
<attribute name="verticalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<row>
|
||||
<property name="text">
|
||||
<string>New Row</string>
|
||||
</property>
|
||||
</row>
|
||||
<row>
|
||||
<property name="text">
|
||||
<string>0</string>
|
||||
</property>
|
||||
</row>
|
||||
<row>
|
||||
<property name="text">
|
||||
<string>1</string>
|
||||
</property>
|
||||
</row>
|
||||
<row>
|
||||
<property name="text">
|
||||
<string>2</string>
|
||||
</property>
|
||||
</row>
|
||||
<row>
|
||||
<property name="text">
|
||||
<string>4</string>
|
||||
</property>
|
||||
</row>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Directory</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Size</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::StandardButton::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>DataDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>DataDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
|
@ -156,6 +156,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
|
|||
#include "yuzu/debugger/console.h"
|
||||
#include "yuzu/debugger/controller.h"
|
||||
#include "yuzu/debugger/wait_tree.h"
|
||||
#include "yuzu/data_dialog.h"
|
||||
#include "yuzu/deps_dialog.h"
|
||||
#include "yuzu/discord.h"
|
||||
#include "yuzu/game_list.h"
|
||||
|
@ -1705,6 +1706,7 @@ void GMainWindow::ConnectMenuEvents() {
|
|||
connect_menu(ui->action_Install_Keys, &GMainWindow::OnInstallDecryptionKeys);
|
||||
connect_menu(ui->action_About, &GMainWindow::OnAbout);
|
||||
connect_menu(ui->action_Eden_Dependencies, &GMainWindow::OnEdenDependencies);
|
||||
connect_menu(ui->action_Data_Manager, &GMainWindow::OnDataDialog);
|
||||
}
|
||||
|
||||
void GMainWindow::UpdateMenuState() {
|
||||
|
@ -3934,6 +3936,11 @@ void GMainWindow::OnEdenDependencies() {
|
|||
depsDialog.exec();
|
||||
}
|
||||
|
||||
void GMainWindow::OnDataDialog() {
|
||||
DataDialog dataDialog(this);
|
||||
dataDialog.exec();
|
||||
}
|
||||
|
||||
void GMainWindow::OnToggleFilterBar() {
|
||||
game_list->SetFilterVisible(ui->action_Show_Filter_Bar->isChecked());
|
||||
if (ui->action_Show_Filter_Bar->isChecked()) {
|
||||
|
|
|
@ -387,6 +387,7 @@ private slots:
|
|||
void OnInstallDecryptionKeys();
|
||||
void OnAbout();
|
||||
void OnEdenDependencies();
|
||||
void OnDataDialog();
|
||||
void OnToggleFilterBar();
|
||||
void OnToggleStatusBar();
|
||||
void OnGameListRefresh();
|
||||
|
|
|
@ -158,7 +158,7 @@
|
|||
</property>
|
||||
<widget class="QMenu" name="menu_cabinet_applet">
|
||||
<property name="title">
|
||||
<string>&Amiibo</string>
|
||||
<string>Am&iibo</string>
|
||||
</property>
|
||||
<addaction name="action_Load_Cabinet_Nickname_Owner"/>
|
||||
<addaction name="action_Load_Cabinet_Eraser"/>
|
||||
|
@ -184,7 +184,7 @@
|
|||
</widget>
|
||||
<widget class="QMenu" name="menuInstall_Firmware">
|
||||
<property name="title">
|
||||
<string>Install Firmware</string>
|
||||
<string>Install &Firmware</string>
|
||||
</property>
|
||||
<addaction name="action_Firmware_From_Folder"/>
|
||||
<addaction name="action_Firmware_From_ZIP"/>
|
||||
|
@ -192,6 +192,7 @@
|
|||
<addaction name="action_Install_Keys"/>
|
||||
<addaction name="menuInstall_Firmware"/>
|
||||
<addaction name="action_Verify_installed_contents"/>
|
||||
<addaction name="action_Data_Manager"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="menu_cabinet_applet"/>
|
||||
<addaction name="action_Load_Album"/>
|
||||
|
@ -497,7 +498,7 @@
|
|||
</action>
|
||||
<action name="action_Install_Keys">
|
||||
<property name="text">
|
||||
<string>Install Decryption Keys</string>
|
||||
<string>Install Decryption &Keys</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_Load_Home_Menu">
|
||||
|
@ -593,6 +594,11 @@
|
|||
<string>&Eden Dependencies</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_Data_Manager">
|
||||
<property name="text">
|
||||
<string>&Data Manager</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="yuzu.qrc"/>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue