Compare commits
2 commits
feature/da
...
master
Author | SHA1 | Date | |
---|---|---|---|
1e1b8ad33f | |||
91493fa39b |
45
.reuse/dep5
|
@ -13,13 +13,12 @@ Copyright: yuzu Emulator Project
|
||||||
License: GPL-2.0-or-later
|
License: GPL-2.0-or-later
|
||||||
|
|
||||||
Files: dist/qt_themes/default/icons/256x256/eden.png
|
Files: dist/qt_themes/default/icons/256x256/eden.png
|
||||||
dist/qt_themes/default/icons/256x256/eden_named.png
|
|
||||||
dist/yuzu.bmp
|
dist/yuzu.bmp
|
||||||
dist/eden.icns
|
dist/yuzu.icns
|
||||||
dist/eden.ico
|
dist/eden.ico
|
||||||
dist/dev.eden_emu.eden.svg
|
dist/eden.svg
|
||||||
Copyright: 2025 Eden Emulator Project
|
Copyright: yuzu Emulator Project
|
||||||
License: GPL-3.0-or-later
|
License: GPL-2.0-or-later
|
||||||
|
|
||||||
Files: dist/qt_themes/qdarkstyle*/LICENSE.*
|
Files: dist/qt_themes/qdarkstyle*/LICENSE.*
|
||||||
dist/qt_themes/qdarkstyle*/style.qrc
|
dist/qt_themes/qdarkstyle*/style.qrc
|
||||||
|
@ -156,39 +155,3 @@ License: BSD-3-Clause
|
||||||
Files: src/android/app/debug.keystore
|
Files: src/android/app/debug.keystore
|
||||||
Copyright: 2023 yuzu Emulator Project
|
Copyright: 2023 yuzu Emulator Project
|
||||||
License: GPL-3.0-or-later
|
License: GPL-3.0-or-later
|
||||||
|
|
||||||
Files: dist/qt_themes/colorful/icons/48x48/user-trash.png
|
|
||||||
dist/qt_themes/colorful/icons/48x48/upload.png
|
|
||||||
dist/qt_themes/colorful/icons/48x48/download.png
|
|
||||||
Copyright: 2014 Uri Herrera
|
|
||||||
1996-2025 KDE Software Foundation
|
|
||||||
License: LGPL-2.0-or-later
|
|
||||||
|
|
||||||
Files: dist/qt_themes/default/icons/48x48/user-trash.png
|
|
||||||
dist/qt_themes/default/icons/48x48/upload.png
|
|
||||||
dist/qt_themes/default/icons/48x48/download.png
|
|
||||||
dist/qt_themes/default_dark/icons/48x48/user-trash.png
|
|
||||||
dist/qt_themes/default_dark/icons/48x48/upload.png
|
|
||||||
dist/qt_themes/default_dark/icons/48x48/download.png
|
|
||||||
Copyright: 2025 Fonticons, Inc.
|
|
||||||
License: CC-BY-4.0
|
|
||||||
Comment: All of these icons have been modified by crueter <crueter@crueter.xyz>
|
|
||||||
|
|
||||||
Files: CMakeModules/CPM.cmake
|
|
||||||
Copyright: 2019-2023 Lars Melchior
|
|
||||||
License: MIT
|
|
||||||
|
|
||||||
Files: CMakeModules/CPMUtil.cmake
|
|
||||||
CMakeModules/CPM.cmake
|
|
||||||
CMakeModules/GetSCMRev.cmake
|
|
||||||
CMakeModules/DetectArchitecture.cmake
|
|
||||||
tools/cpm/*
|
|
||||||
tools/update-cpm.sh
|
|
||||||
tools/shellcheck.sh
|
|
||||||
docs/CPMUtil.md
|
|
||||||
**cpmfile.json
|
|
||||||
Copyright: 2025 crueter <crueter@crueter.xyz>
|
|
||||||
License: GPL-3.0-or-later
|
|
||||||
Comment: CPM.cmake has had additional modifications from crueter to better work with CPMUtil
|
|
||||||
https://git.crueter.xyz/CMake/CPMUtil
|
|
||||||
https://git.crueter.xyz/CMake/Modules
|
|
||||||
|
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
BIN
dist/qt_themes/colorful/icons/48x48/download.png
vendored
Before Width: | Height: | Size: 1.4 KiB |
BIN
dist/qt_themes/colorful/icons/48x48/upload.png
vendored
Before Width: | Height: | Size: 1.4 KiB |
BIN
dist/qt_themes/colorful/icons/48x48/user-trash.png
vendored
Before Width: | Height: | Size: 1.4 KiB |
3
dist/qt_themes/colorful/style.qrc
vendored
|
@ -18,9 +18,6 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
<file alias="48x48/bad_folder.png">icons/48x48/bad_folder.png</file>
|
<file alias="48x48/bad_folder.png">icons/48x48/bad_folder.png</file>
|
||||||
<file alias="48x48/chip.png">icons/48x48/chip.png</file>
|
<file alias="48x48/chip.png">icons/48x48/chip.png</file>
|
||||||
<file alias="48x48/folder.png">icons/48x48/folder.png</file>
|
<file alias="48x48/folder.png">icons/48x48/folder.png</file>
|
||||||
<file alias="48x48/user-trash.png">icons/48x48/user-trash.png</file>
|
|
||||||
<file alias="48x48/download.png">icons/48x48/download.png</file>
|
|
||||||
<file alias="48x48/upload.png">icons/48x48/upload.png</file>
|
|
||||||
<file alias="48x48/list-add.png">icons/48x48/list-add.png</file>
|
<file alias="48x48/list-add.png">icons/48x48/list-add.png</file>
|
||||||
<file alias="48x48/no_avatar.png">icons/48x48/no_avatar.png</file>
|
<file alias="48x48/no_avatar.png">icons/48x48/no_avatar.png</file>
|
||||||
<file alias="48x48/sd_card.png">icons/48x48/sd_card.png</file>
|
<file alias="48x48/sd_card.png">icons/48x48/sd_card.png</file>
|
||||||
|
|
|
@ -11,9 +11,6 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
<file alias="48x48/bad_folder.png">../colorful/icons/48x48/bad_folder.png</file>
|
<file alias="48x48/bad_folder.png">../colorful/icons/48x48/bad_folder.png</file>
|
||||||
<file alias="48x48/chip.png">../colorful/icons/48x48/chip.png</file>
|
<file alias="48x48/chip.png">../colorful/icons/48x48/chip.png</file>
|
||||||
<file alias="48x48/folder.png">../colorful/icons/48x48/folder.png</file>
|
<file alias="48x48/folder.png">../colorful/icons/48x48/folder.png</file>
|
||||||
<file alias="48x48/user-trash.png">../colorful/icons/48x48/user-trash.png</file>
|
|
||||||
<file alias="48x48/download.png">../colorful/icons/48x48/download.png</file>
|
|
||||||
<file alias="48x48/upload.png">../colorful/icons/48x48/upload.png</file>
|
|
||||||
<file alias="48x48/list-add.png">../colorful/icons/48x48/list-add.png</file>
|
<file alias="48x48/list-add.png">../colorful/icons/48x48/list-add.png</file>
|
||||||
<file alias="48x48/sd_card.png">../colorful/icons/48x48/sd_card.png</file>
|
<file alias="48x48/sd_card.png">../colorful/icons/48x48/sd_card.png</file>
|
||||||
<file alias="256x256/plus_folder.png">../colorful/icons/256x256/plus_folder.png</file>
|
<file alias="256x256/plus_folder.png">../colorful/icons/256x256/plus_folder.png</file>
|
||||||
|
|
3
dist/qt_themes/default/default.qrc
vendored
|
@ -14,9 +14,6 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
<file alias="48x48/bad_folder.png">icons/48x48/bad_folder.png</file>
|
<file alias="48x48/bad_folder.png">icons/48x48/bad_folder.png</file>
|
||||||
<file alias="48x48/chip.png">icons/48x48/chip.png</file>
|
<file alias="48x48/chip.png">icons/48x48/chip.png</file>
|
||||||
<file alias="48x48/folder.png">icons/48x48/folder.png</file>
|
<file alias="48x48/folder.png">icons/48x48/folder.png</file>
|
||||||
<file alias="48x48/user-trash.png">icons/48x48/user-trash.png</file>
|
|
||||||
<file alias="48x48/download.png">icons/48x48/download.png</file>
|
|
||||||
<file alias="48x48/upload.png">icons/48x48/upload.png</file>
|
|
||||||
<file alias="48x48/list-add.png">icons/48x48/list-add.png</file>
|
<file alias="48x48/list-add.png">icons/48x48/list-add.png</file>
|
||||||
<file alias="48x48/sd_card.png">icons/48x48/sd_card.png</file>
|
<file alias="48x48/sd_card.png">icons/48x48/sd_card.png</file>
|
||||||
<file alias="48x48/star.png">icons/48x48/star.png</file>
|
<file alias="48x48/star.png">icons/48x48/star.png</file>
|
||||||
|
|
BIN
dist/qt_themes/default/icons/256x256/eden.png
vendored
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 4.9 KiB |
BIN
dist/qt_themes/default/icons/48x48/download.png
vendored
Before Width: | Height: | Size: 853 B |
BIN
dist/qt_themes/default/icons/48x48/upload.png
vendored
Before Width: | Height: | Size: 820 B |
BIN
dist/qt_themes/default/icons/48x48/user-trash.png
vendored
Before Width: | Height: | Size: 584 B |
3
dist/qt_themes/default_dark/style.qrc
vendored
|
@ -13,9 +13,6 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
<file alias="48x48/bad_folder.png">../colorful/icons/48x48/bad_folder.png</file>
|
<file alias="48x48/bad_folder.png">../colorful/icons/48x48/bad_folder.png</file>
|
||||||
<file alias="48x48/chip.png">../colorful/icons/48x48/chip.png</file>
|
<file alias="48x48/chip.png">../colorful/icons/48x48/chip.png</file>
|
||||||
<file alias="48x48/folder.png">../colorful/icons/48x48/folder.png</file>
|
<file alias="48x48/folder.png">../colorful/icons/48x48/folder.png</file>
|
||||||
<file alias="48x48/user-trash.png">../colorful/icons/48x48/user-trash.png</file>
|
|
||||||
<file alias="48x48/download.png">../colorful/icons/48x48/download.png</file>
|
|
||||||
<file alias="48x48/upload.png">../colorful/icons/48x48/upload.png</file>
|
|
||||||
<file alias="48x48/no_avatar.png">../qdarkstyle/icons/48x48/no_avatar.png</file>
|
<file alias="48x48/no_avatar.png">../qdarkstyle/icons/48x48/no_avatar.png</file>
|
||||||
<file alias="48x48/list-add.png">../colorful/icons/48x48/list-add.png</file>
|
<file alias="48x48/list-add.png">../colorful/icons/48x48/list-add.png</file>
|
||||||
<file alias="48x48/sd_card.png">../colorful/icons/48x48/sd_card.png</file>
|
<file alias="48x48/sd_card.png">../colorful/icons/48x48/sd_card.png</file>
|
||||||
|
|
BIN
dist/qt_themes/qdarkstyle/icons/48x48/download.png
vendored
Before Width: | Height: | Size: 883 B |
BIN
dist/qt_themes/qdarkstyle/icons/48x48/upload.png
vendored
Before Width: | Height: | Size: 853 B |
BIN
dist/qt_themes/qdarkstyle/icons/48x48/user-trash.png
vendored
Before Width: | Height: | Size: 584 B |
3
dist/qt_themes/qdarkstyle/style.qrc
vendored
|
@ -9,9 +9,6 @@
|
||||||
<file alias="48x48/bad_folder.png">icons/48x48/bad_folder.png</file>
|
<file alias="48x48/bad_folder.png">icons/48x48/bad_folder.png</file>
|
||||||
<file alias="48x48/chip.png">icons/48x48/chip.png</file>
|
<file alias="48x48/chip.png">icons/48x48/chip.png</file>
|
||||||
<file alias="48x48/folder.png">icons/48x48/folder.png</file>
|
<file alias="48x48/folder.png">icons/48x48/folder.png</file>
|
||||||
<file alias="48x48/user-trash.png">icons/48x48/user-trash.png</file>
|
|
||||||
<file alias="48x48/download.png">icons/48x48/download.png</file>
|
|
||||||
<file alias="48x48/upload.png">icons/48x48/upload.png</file>
|
|
||||||
<file alias="48x48/no_avatar.png">icons/48x48/no_avatar.png</file>
|
<file alias="48x48/no_avatar.png">icons/48x48/no_avatar.png</file>
|
||||||
<file alias="48x48/list-add.png">icons/48x48/list-add.png</file>
|
<file alias="48x48/list-add.png">icons/48x48/list-add.png</file>
|
||||||
<file alias="48x48/sd_card.png">icons/48x48/sd_card.png</file>
|
<file alias="48x48/sd_card.png">icons/48x48/sd_card.png</file>
|
||||||
|
|
|
@ -6,9 +6,6 @@
|
||||||
<file alias="48x48/bad_folder.png">../qdarkstyle/icons/48x48/bad_folder.png</file>
|
<file alias="48x48/bad_folder.png">../qdarkstyle/icons/48x48/bad_folder.png</file>
|
||||||
<file alias="48x48/chip.png">../qdarkstyle/icons/48x48/chip.png</file>
|
<file alias="48x48/chip.png">../qdarkstyle/icons/48x48/chip.png</file>
|
||||||
<file alias="48x48/folder.png">../qdarkstyle/icons/48x48/folder.png</file>
|
<file alias="48x48/folder.png">../qdarkstyle/icons/48x48/folder.png</file>
|
||||||
<file alias="48x48/user-trash.png">../qdarkstyle/icons/48x48/user-trash.png</file>
|
|
||||||
<file alias="48x48/download.png">../qdarkstyle/icons/48x48/download.png</file>
|
|
||||||
<file alias="48x48/upload.png">../qdarkstyle/icons/48x48/upload.png</file>
|
|
||||||
<file alias="48x48/no_avatar.png">../qdarkstyle/icons/48x48/no_avatar.png</file>
|
<file alias="48x48/no_avatar.png">../qdarkstyle/icons/48x48/no_avatar.png</file>
|
||||||
<file alias="48x48/list-add.png">../qdarkstyle/icons/48x48/list-add.png</file>
|
<file alias="48x48/list-add.png">../qdarkstyle/icons/48x48/list-add.png</file>
|
||||||
<file alias="48x48/sd_card.png">../qdarkstyle/icons/48x48/sd_card.png</file>
|
<file alias="48x48/sd_card.png">../qdarkstyle/icons/48x48/sd_card.png</file>
|
||||||
|
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 244 KiB After Width: | Height: | Size: 438 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 112 KiB After Width: | Height: | Size: 112 KiB |
|
@ -161,7 +161,7 @@ struct Values {
|
||||||
Category::LibraryApplet};
|
Category::LibraryApplet};
|
||||||
Setting<AppletMode> photo_viewer_applet_mode{
|
Setting<AppletMode> photo_viewer_applet_mode{
|
||||||
linkage, AppletMode::LLE, "photo_viewer_applet_mode", Category::LibraryApplet};
|
linkage, AppletMode::LLE, "photo_viewer_applet_mode", Category::LibraryApplet};
|
||||||
Setting<AppletMode> offline_web_applet_mode{linkage, AppletMode::HLE, "offline_web_applet_mode",
|
Setting<AppletMode> offline_web_applet_mode{linkage, AppletMode::LLE, "offline_web_applet_mode",
|
||||||
Category::LibraryApplet};
|
Category::LibraryApplet};
|
||||||
Setting<AppletMode> login_share_applet_mode{linkage, AppletMode::HLE, "login_share_applet_mode",
|
Setting<AppletMode> login_share_applet_mode{linkage, AppletMode::HLE, "login_share_applet_mode",
|
||||||
Category::LibraryApplet};
|
Category::LibraryApplet};
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
@ -68,42 +71,6 @@ std::string ResolveURL(const std::string& url) {
|
||||||
return url.substr(0, index) + "lp1" + url.substr(index + 1);
|
return url.substr(0, index) + "lp1" + url.substr(index + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
WebArgInputTLVMap ReadWebArgs(const std::vector<u8>& web_arg, WebArgHeader& web_arg_header) {
|
|
||||||
std::memcpy(&web_arg_header, web_arg.data(), sizeof(WebArgHeader));
|
|
||||||
|
|
||||||
if (web_arg.size() == sizeof(WebArgHeader)) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
WebArgInputTLVMap input_tlv_map;
|
|
||||||
|
|
||||||
u64 current_offset = sizeof(WebArgHeader);
|
|
||||||
|
|
||||||
for (std::size_t i = 0; i < web_arg_header.total_tlv_entries; ++i) {
|
|
||||||
if (web_arg.size() < current_offset + sizeof(WebArgInputTLV)) {
|
|
||||||
return input_tlv_map;
|
|
||||||
}
|
|
||||||
|
|
||||||
WebArgInputTLV input_tlv;
|
|
||||||
std::memcpy(&input_tlv, web_arg.data() + current_offset, sizeof(WebArgInputTLV));
|
|
||||||
|
|
||||||
current_offset += sizeof(WebArgInputTLV);
|
|
||||||
|
|
||||||
if (web_arg.size() < current_offset + input_tlv.arg_data_size) {
|
|
||||||
return input_tlv_map;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<u8> data(input_tlv.arg_data_size);
|
|
||||||
std::memcpy(data.data(), web_arg.data() + current_offset, input_tlv.arg_data_size);
|
|
||||||
|
|
||||||
current_offset += input_tlv.arg_data_size;
|
|
||||||
|
|
||||||
input_tlv_map.insert_or_assign(input_tlv.input_tlv_type, std::move(data));
|
|
||||||
}
|
|
||||||
|
|
||||||
return input_tlv_map;
|
|
||||||
}
|
|
||||||
|
|
||||||
FileSys::VirtualFile GetOfflineRomFS(Core::System& system, u64 title_id,
|
FileSys::VirtualFile GetOfflineRomFS(Core::System& system, u64 title_id,
|
||||||
FileSys::ContentRecordType nca_type) {
|
FileSys::ContentRecordType nca_type) {
|
||||||
if (nca_type == FileSys::ContentRecordType::Data) {
|
if (nca_type == FileSys::ContentRecordType::Data) {
|
||||||
|
@ -144,6 +111,43 @@ FileSys::VirtualFile GetOfflineRomFS(Core::System& system, u64 title_id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef YUZU_USE_QT_WEB_ENGINE
|
||||||
|
WebArgInputTLVMap ReadWebArgs(const std::vector<u8>& web_arg, WebArgHeader& web_arg_header) {
|
||||||
|
std::memcpy(&web_arg_header, web_arg.data(), sizeof(WebArgHeader));
|
||||||
|
|
||||||
|
if (web_arg.size() == sizeof(WebArgHeader)) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
WebArgInputTLVMap input_tlv_map;
|
||||||
|
|
||||||
|
u64 current_offset = sizeof(WebArgHeader);
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < web_arg_header.total_tlv_entries; ++i) {
|
||||||
|
if (web_arg.size() < current_offset + sizeof(WebArgInputTLV)) {
|
||||||
|
return input_tlv_map;
|
||||||
|
}
|
||||||
|
|
||||||
|
WebArgInputTLV input_tlv;
|
||||||
|
std::memcpy(&input_tlv, web_arg.data() + current_offset, sizeof(WebArgInputTLV));
|
||||||
|
|
||||||
|
current_offset += sizeof(WebArgInputTLV);
|
||||||
|
|
||||||
|
if (web_arg.size() < current_offset + input_tlv.arg_data_size) {
|
||||||
|
return input_tlv_map;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<u8> data(input_tlv.arg_data_size);
|
||||||
|
std::memcpy(data.data(), web_arg.data() + current_offset, input_tlv.arg_data_size);
|
||||||
|
|
||||||
|
current_offset += input_tlv.arg_data_size;
|
||||||
|
|
||||||
|
input_tlv_map.insert_or_assign(input_tlv.input_tlv_type, std::move(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
return input_tlv_map;
|
||||||
|
}
|
||||||
|
|
||||||
void ExtractSharedFonts(Core::System& system) {
|
void ExtractSharedFonts(Core::System& system) {
|
||||||
static constexpr std::array<const char*, 7> DECRYPTED_SHARED_FONTS{
|
static constexpr std::array<const char*, 7> DECRYPTED_SHARED_FONTS{
|
||||||
"FontStandard.ttf",
|
"FontStandard.ttf",
|
||||||
|
@ -221,6 +225,7 @@ void ExtractSharedFonts(Core::System& system) {
|
||||||
FileSys::VfsRawCopy(decrypted_font, out_file);
|
FileSys::VfsRawCopy(decrypted_font, out_file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
@ -232,6 +237,7 @@ WebBrowser::WebBrowser(Core::System& system_, std::shared_ptr<Applet> applet_,
|
||||||
WebBrowser::~WebBrowser() = default;
|
WebBrowser::~WebBrowser() = default;
|
||||||
|
|
||||||
void WebBrowser::Initialize() {
|
void WebBrowser::Initialize() {
|
||||||
|
#ifdef YUZU_USE_QT_WEB_ENGINE
|
||||||
FrontendApplet::Initialize();
|
FrontendApplet::Initialize();
|
||||||
|
|
||||||
LOG_INFO(Service_AM, "Initializing Web Browser Applet.");
|
LOG_INFO(Service_AM, "Initializing Web Browser Applet.");
|
||||||
|
@ -284,6 +290,7 @@ void WebBrowser::Initialize() {
|
||||||
ASSERT_MSG(false, "Invalid ShimKind={}", web_arg_header.shim_kind);
|
ASSERT_MSG(false, "Invalid ShimKind={}", web_arg_header.shim_kind);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
Result WebBrowser::GetStatus() const {
|
Result WebBrowser::GetStatus() const {
|
||||||
|
@ -295,6 +302,7 @@ void WebBrowser::ExecuteInteractive() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebBrowser::Execute() {
|
void WebBrowser::Execute() {
|
||||||
|
#ifdef YUZU_USE_QT_WEB_ENGINE
|
||||||
switch (web_arg_header.shim_kind) {
|
switch (web_arg_header.shim_kind) {
|
||||||
case ShimKind::Shop:
|
case ShimKind::Shop:
|
||||||
ExecuteShop();
|
ExecuteShop();
|
||||||
|
@ -322,6 +330,10 @@ void WebBrowser::Execute() {
|
||||||
WebBrowserExit(WebExitReason::EndButtonPressed);
|
WebBrowserExit(WebExitReason::EndButtonPressed);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
LOG_INFO(Service_AM, "Web Browser Applet disabled, skipping.");
|
||||||
|
WebBrowserExit(WebExitReason::EndButtonPressed);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebBrowser::ExtractOfflineRomFS() {
|
void WebBrowser::ExtractOfflineRomFS() {
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
# SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
# SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
@ -10,7 +7,6 @@ add_library(frontend_common STATIC
|
||||||
content_manager.h
|
content_manager.h
|
||||||
firmware_manager.h
|
firmware_manager.h
|
||||||
firmware_manager.cpp
|
firmware_manager.cpp
|
||||||
data_manager.h data_manager.cpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
create_target_directory_groups(frontend_common)
|
create_target_directory_groups(frontend_common)
|
||||||
|
|
|
@ -1,77 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#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 std::string &user_id)
|
|
||||||
{
|
|
||||||
const fs::path nand_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir);
|
|
||||||
|
|
||||||
switch (dir) {
|
|
||||||
case DataDir::Saves:
|
|
||||||
return (nand_dir / "user" / "save" / "0000000000000000" / user_id).string();
|
|
||||||
case DataDir::UserNand:
|
|
||||||
return (nand_dir / "user" / "Contents" / "registered").string();
|
|
||||||
case DataDir::SysNand:
|
|
||||||
// NB: do NOT delete save
|
|
||||||
// that contains profile data and other stuff
|
|
||||||
return (nand_dir / "system" / "Contents" / "registered").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, const std::string &user_id)
|
|
||||||
{
|
|
||||||
fs::path data_dir = GetDataDir(dir, user_id);
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#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, const std::string &user_id = "");
|
|
||||||
|
|
||||||
u64 ClearDir(DataDir dir, const std::string &user_id = "");
|
|
||||||
|
|
||||||
const std::string ReadableBytesSize(u64 size);
|
|
||||||
|
|
||||||
u64 DataDirSize(DataDir dir);
|
|
||||||
|
|
||||||
}; // namespace FrontendCommon::DataManager
|
|
||||||
|
|
||||||
#endif // DATA_MANAGER_H
|
|
|
@ -4,6 +4,9 @@
|
||||||
# SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
# SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
# 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
|
add_library(qt_common STATIC
|
||||||
qt_common.h
|
qt_common.h
|
||||||
qt_common.cpp
|
qt_common.cpp
|
||||||
|
@ -24,8 +27,6 @@ add_library(qt_common STATIC
|
||||||
qt_rom_util.h qt_rom_util.cpp
|
qt_rom_util.h qt_rom_util.cpp
|
||||||
qt_applet_util.h qt_applet_util.cpp
|
qt_applet_util.h qt_applet_util.cpp
|
||||||
qt_progress_dialog.h qt_progress_dialog.cpp
|
qt_progress_dialog.h qt_progress_dialog.cpp
|
||||||
qt_string_lookup.h
|
|
||||||
qt_compress.h qt_compress.cpp
|
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -36,29 +37,9 @@ if (ENABLE_QT)
|
||||||
target_link_libraries(qt_common PRIVATE Qt6::Widgets)
|
target_link_libraries(qt_common PRIVATE Qt6::Widgets)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_compile_definitions(qt_common PUBLIC
|
|
||||||
# Use QStringBuilder for string concatenation to reduce
|
|
||||||
# the overall number of temporary strings created.
|
|
||||||
QT_USE_QSTRINGBUILDER
|
|
||||||
|
|
||||||
# Disable implicit conversions from/to C strings
|
|
||||||
QT_NO_CAST_FROM_ASCII
|
|
||||||
QT_NO_CAST_TO_ASCII
|
|
||||||
|
|
||||||
# Disable implicit type narrowing in signal/slot connect() calls.
|
|
||||||
QT_NO_NARROWING_CONVERSIONS_IN_CONNECT
|
|
||||||
|
|
||||||
# Disable unsafe overloads of QProcess' start() function.
|
|
||||||
QT_NO_PROCESS_COMBINED_ARGUMENT_START
|
|
||||||
|
|
||||||
# Disable implicit QString->QUrl conversions to enforce use of proper resolving functions.
|
|
||||||
QT_NO_URL_CAST_FROM_STRING
|
|
||||||
)
|
|
||||||
|
|
||||||
add_subdirectory(externals)
|
add_subdirectory(externals)
|
||||||
|
|
||||||
target_link_libraries(qt_common PRIVATE core Qt6::Core Qt6::Concurrent SimpleIni::SimpleIni QuaZip::QuaZip)
|
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)
|
if (NOT APPLE AND ENABLE_OPENGL)
|
||||||
target_compile_definitions(qt_common PUBLIC HAS_OPENGL)
|
target_compile_definitions(qt_common PUBLIC HAS_OPENGL)
|
||||||
|
|
3
src/qt_common/externals/CMakeLists.txt
vendored
|
@ -16,4 +16,5 @@ set_directory_properties(PROPERTIES EXCLUDE_FROM_ALL ON)
|
||||||
AddJsonPackage(quazip)
|
AddJsonPackage(quazip)
|
||||||
|
|
||||||
# frozen
|
# frozen
|
||||||
AddJsonPackage(frozen)
|
# TODO(crueter): Qt String Lookup
|
||||||
|
# AddJsonPackage(frozen)
|
||||||
|
|
|
@ -1,354 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#include "qt_compress.h"
|
|
||||||
#include "quazipfileinfo.h"
|
|
||||||
|
|
||||||
#include <QDirIterator>
|
|
||||||
|
|
||||||
/** This is a modified version of JlCompress **/
|
|
||||||
namespace QtCommon::Compress {
|
|
||||||
|
|
||||||
bool compressDir(QString fileCompressed,
|
|
||||||
QString dir,
|
|
||||||
const JlCompress::Options &options,
|
|
||||||
QtCommon::QtProgressCallback callback)
|
|
||||||
{
|
|
||||||
// Create zip
|
|
||||||
QuaZip zip(fileCompressed);
|
|
||||||
QDir().mkpath(QFileInfo(fileCompressed).absolutePath());
|
|
||||||
if (!zip.open(QuaZip::mdCreate)) {
|
|
||||||
QFile::remove(fileCompressed);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// See how big the overall fs structure is
|
|
||||||
// good approx. of total progress
|
|
||||||
// TODO(crueter): QDirListing impl
|
|
||||||
QDirIterator iter(dir,
|
|
||||||
QDir::NoDotAndDotDot | QDir::Hidden | QDir::Files,
|
|
||||||
QDirIterator::Subdirectories);
|
|
||||||
|
|
||||||
std::size_t total = 0;
|
|
||||||
while (iter.hasNext()) {
|
|
||||||
total += iter.nextFileInfo().size();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t progress = 0;
|
|
||||||
callback(total, progress);
|
|
||||||
|
|
||||||
// Add the files and subdirectories
|
|
||||||
if (!compressSubDir(&zip, dir, dir, options, total, progress, callback)) {
|
|
||||||
QFile::remove(fileCompressed);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close zip
|
|
||||||
zip.close();
|
|
||||||
if (zip.getZipError() != 0) {
|
|
||||||
QFile::remove(fileCompressed);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool compressSubDir(QuaZip *zip,
|
|
||||||
QString dir,
|
|
||||||
QString origDir,
|
|
||||||
const JlCompress::Options &options,
|
|
||||||
std::size_t total,
|
|
||||||
std::size_t &progress,
|
|
||||||
QtProgressCallback callback)
|
|
||||||
{
|
|
||||||
// zip: object where to add the file
|
|
||||||
// dir: current real directory
|
|
||||||
// origDir: original real directory
|
|
||||||
// (path(dir)-path(origDir)) = path inside the zip object
|
|
||||||
|
|
||||||
if (!zip)
|
|
||||||
return false;
|
|
||||||
if (zip->getMode() != QuaZip::mdCreate && zip->getMode() != QuaZip::mdAppend
|
|
||||||
&& zip->getMode() != QuaZip::mdAdd)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
QDir directory(dir);
|
|
||||||
if (!directory.exists())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
|
|
||||||
QDir origDirectory(origDir);
|
|
||||||
if (dir != origDir) {
|
|
||||||
QuaZipFile dirZipFile(zip);
|
|
||||||
std::unique_ptr<QuaZipNewInfo> qzni;
|
|
||||||
if (options.getDateTime().isNull()) {
|
|
||||||
qzni = std::make_unique<QuaZipNewInfo>(origDirectory.relativeFilePath(dir)
|
|
||||||
+ QLatin1String("/"),
|
|
||||||
dir);
|
|
||||||
} else {
|
|
||||||
qzni = std::make_unique<QuaZipNewInfo>(origDirectory.relativeFilePath(dir)
|
|
||||||
+ QLatin1String("/"),
|
|
||||||
dir,
|
|
||||||
options.getDateTime());
|
|
||||||
}
|
|
||||||
if (!dirZipFile.open(QIODevice::WriteOnly, *qzni, nullptr, 0, 0)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
dirZipFile.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
// For each subfolder
|
|
||||||
QFileInfoList subfiles = directory.entryInfoList(QDir::AllDirs | QDir::NoDotAndDotDot
|
|
||||||
| QDir::Hidden | QDir::Dirs);
|
|
||||||
for (const auto &file : std::as_const(subfiles)) {
|
|
||||||
if (!compressSubDir(
|
|
||||||
zip, file.absoluteFilePath(), origDir, options, total, progress, callback)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// For each file in directory
|
|
||||||
QFileInfoList files = directory.entryInfoList(QDir::Hidden | QDir::Files);
|
|
||||||
for (const auto &file : std::as_const(files)) {
|
|
||||||
// If it's not a file or it's the compressed file being created
|
|
||||||
if (!file.isFile() || file.absoluteFilePath() == zip->getZipName())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Create relative name for the compressed file
|
|
||||||
QString filename = origDirectory.relativeFilePath(file.absoluteFilePath());
|
|
||||||
|
|
||||||
// Compress the file
|
|
||||||
if (!compressFile(zip, file.absoluteFilePath(), filename, options, total, progress, callback)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool compressFile(QuaZip *zip,
|
|
||||||
QString fileName,
|
|
||||||
QString fileDest,
|
|
||||||
const JlCompress::Options &options,
|
|
||||||
std::size_t total,
|
|
||||||
std::size_t &progress,
|
|
||||||
QtCommon::QtProgressCallback callback)
|
|
||||||
{
|
|
||||||
// zip: object where to add the file
|
|
||||||
// fileName: real file name
|
|
||||||
// fileDest: file name inside the zip object
|
|
||||||
|
|
||||||
if (!zip)
|
|
||||||
return false;
|
|
||||||
if (zip->getMode() != QuaZip::mdCreate && zip->getMode() != QuaZip::mdAppend
|
|
||||||
&& zip->getMode() != QuaZip::mdAdd)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
QuaZipFile outFile(zip);
|
|
||||||
if (options.getDateTime().isNull()) {
|
|
||||||
if (!outFile.open(QIODevice::WriteOnly,
|
|
||||||
QuaZipNewInfo(fileDest, fileName),
|
|
||||||
nullptr,
|
|
||||||
0,
|
|
||||||
options.getCompressionMethod(),
|
|
||||||
options.getCompressionLevel()))
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
if (!outFile.open(QIODevice::WriteOnly,
|
|
||||||
QuaZipNewInfo(fileDest, fileName, options.getDateTime()),
|
|
||||||
nullptr,
|
|
||||||
0,
|
|
||||||
options.getCompressionMethod(),
|
|
||||||
options.getCompressionLevel()))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
QFileInfo input(fileName);
|
|
||||||
if (quazip_is_symlink(input)) {
|
|
||||||
// Not sure if we should use any specialized codecs here.
|
|
||||||
// After all, a symlink IS just a byte array. And
|
|
||||||
// this is mostly for Linux, where UTF-8 is ubiquitous these days.
|
|
||||||
QString path = quazip_symlink_target(input);
|
|
||||||
QString relativePath = input.dir().relativeFilePath(path);
|
|
||||||
outFile.write(QFile::encodeName(relativePath));
|
|
||||||
} else {
|
|
||||||
QFile inFile;
|
|
||||||
inFile.setFileName(fileName);
|
|
||||||
if (!inFile.open(QIODevice::ReadOnly)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!copyData(inFile, outFile, total, progress, callback) || outFile.getZipError() != UNZ_OK) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
inFile.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
outFile.close();
|
|
||||||
return outFile.getZipError() == UNZ_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool copyData(QIODevice &inFile,
|
|
||||||
QIODevice &outFile,
|
|
||||||
std::size_t total,
|
|
||||||
std::size_t &progress,
|
|
||||||
QtProgressCallback callback)
|
|
||||||
{
|
|
||||||
while (!inFile.atEnd()) {
|
|
||||||
char buf[4096];
|
|
||||||
qint64 readLen = inFile.read(buf, 4096);
|
|
||||||
if (readLen <= 0)
|
|
||||||
return false;
|
|
||||||
if (outFile.write(buf, readLen) != readLen)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
progress += readLen;
|
|
||||||
if (!callback(total, progress)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList extractDir(QString fileCompressed, QString dir, QtCommon::QtProgressCallback callback)
|
|
||||||
{
|
|
||||||
// Open zip
|
|
||||||
QuaZip zip(fileCompressed);
|
|
||||||
return extractDir(zip, dir, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList extractDir(QuaZip &zip, const QString &dir, QtCommon::QtProgressCallback callback)
|
|
||||||
{
|
|
||||||
if (!zip.open(QuaZip::mdUnzip)) {
|
|
||||||
return QStringList();
|
|
||||||
}
|
|
||||||
QString cleanDir = QDir::cleanPath(dir);
|
|
||||||
QDir directory(cleanDir);
|
|
||||||
QString absCleanDir = directory.absolutePath();
|
|
||||||
if (!absCleanDir.endsWith(QLatin1Char('/'))) // It only ends with / if it's the FS root.
|
|
||||||
absCleanDir += QLatin1Char('/');
|
|
||||||
QStringList extracted;
|
|
||||||
if (!zip.goToFirstFile()) {
|
|
||||||
return QStringList();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t total = 0;
|
|
||||||
for (const QuaZipFileInfo64 &info : zip.getFileInfoList64()) {
|
|
||||||
total += info.uncompressedSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t progress = 0;
|
|
||||||
callback(total, progress);
|
|
||||||
|
|
||||||
do {
|
|
||||||
QString name = zip.getCurrentFileName();
|
|
||||||
QString absFilePath = directory.absoluteFilePath(name);
|
|
||||||
QString absCleanPath = QDir::cleanPath(absFilePath);
|
|
||||||
if (!absCleanPath.startsWith(absCleanDir))
|
|
||||||
continue;
|
|
||||||
if (!extractFile(&zip, QLatin1String(""), absFilePath, total, progress, callback)) {
|
|
||||||
removeFile(extracted);
|
|
||||||
return QStringList();
|
|
||||||
}
|
|
||||||
extracted.append(absFilePath);
|
|
||||||
} while (zip.goToNextFile());
|
|
||||||
|
|
||||||
// Close zip
|
|
||||||
zip.close();
|
|
||||||
if (zip.getZipError() != 0) {
|
|
||||||
removeFile(extracted);
|
|
||||||
return QStringList();
|
|
||||||
}
|
|
||||||
|
|
||||||
return extracted;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool extractFile(QuaZip *zip,
|
|
||||||
QString fileName,
|
|
||||||
QString fileDest,
|
|
||||||
std::size_t total,
|
|
||||||
std::size_t &progress,
|
|
||||||
QtCommon::QtProgressCallback callback)
|
|
||||||
{
|
|
||||||
// zip: object where to add the file
|
|
||||||
// filename: real file name
|
|
||||||
// fileincompress: file name of the compressed file
|
|
||||||
|
|
||||||
if (!zip)
|
|
||||||
return false;
|
|
||||||
if (zip->getMode() != QuaZip::mdUnzip)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!fileName.isEmpty())
|
|
||||||
zip->setCurrentFile(fileName);
|
|
||||||
QuaZipFile inFile(zip);
|
|
||||||
if (!inFile.open(QIODevice::ReadOnly) || inFile.getZipError() != UNZ_OK)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Check existence of resulting file
|
|
||||||
QDir curDir;
|
|
||||||
if (fileDest.endsWith(QLatin1String("/"))) {
|
|
||||||
if (!curDir.mkpath(fileDest)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!curDir.mkpath(QFileInfo(fileDest).absolutePath())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QuaZipFileInfo64 info;
|
|
||||||
if (!zip->getCurrentFileInfo(&info))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
QFile::Permissions srcPerm = info.getPermissions();
|
|
||||||
if (fileDest.endsWith(QLatin1String("/")) && QFileInfo(fileDest).isDir()) {
|
|
||||||
if (srcPerm != 0) {
|
|
||||||
QFile(fileDest).setPermissions(srcPerm);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (info.isSymbolicLink()) {
|
|
||||||
QString target = QFile::decodeName(inFile.readAll());
|
|
||||||
return QFile::link(target, fileDest);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open resulting file
|
|
||||||
QFile outFile;
|
|
||||||
outFile.setFileName(fileDest);
|
|
||||||
if (!outFile.open(QIODevice::WriteOnly))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Copy data
|
|
||||||
if (!copyData(inFile, outFile, total, progress, callback) || inFile.getZipError() != UNZ_OK) {
|
|
||||||
outFile.close();
|
|
||||||
removeFile(QStringList(fileDest));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
outFile.close();
|
|
||||||
|
|
||||||
// Close file
|
|
||||||
inFile.close();
|
|
||||||
if (inFile.getZipError() != UNZ_OK) {
|
|
||||||
removeFile(QStringList(fileDest));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (srcPerm != 0) {
|
|
||||||
outFile.setPermissions(srcPerm);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool removeFile(QStringList listFile)
|
|
||||||
{
|
|
||||||
bool ret = true;
|
|
||||||
// For each file
|
|
||||||
for (int i = 0; i < listFile.count(); i++) {
|
|
||||||
// Remove
|
|
||||||
ret = ret && QFile::remove(listFile.at(i));
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace QtCommon::Compress
|
|
|
@ -1,71 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QDir>
|
|
||||||
#include <QString>
|
|
||||||
#include <JlCompress.h>
|
|
||||||
#include "qt_common/qt_common.h"
|
|
||||||
|
|
||||||
/** This is a modified version of JlCompress **/
|
|
||||||
namespace QtCommon::Compress {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Compress an entire directory and report its progress.
|
|
||||||
* @param fileCompressed Destination file
|
|
||||||
* @param dir The directory to compress
|
|
||||||
* @param options Compression level, etc
|
|
||||||
* @param callback Callback that takes in two std::size_t (total, progress) and returns false if the current operation should be cancelled.
|
|
||||||
*/
|
|
||||||
bool compressDir(QString fileCompressed,
|
|
||||||
QString dir,
|
|
||||||
const JlCompress::Options& options = JlCompress::Options(),
|
|
||||||
QtCommon::QtProgressCallback callback = {});
|
|
||||||
|
|
||||||
// Internal //
|
|
||||||
bool compressSubDir(QuaZip *zip,
|
|
||||||
QString dir,
|
|
||||||
QString origDir,
|
|
||||||
const JlCompress::Options &options,
|
|
||||||
std::size_t total,
|
|
||||||
std::size_t &progress,
|
|
||||||
QtCommon::QtProgressCallback callback);
|
|
||||||
|
|
||||||
bool compressFile(QuaZip *zip,
|
|
||||||
QString fileName,
|
|
||||||
QString fileDest,
|
|
||||||
const JlCompress::Options &options,
|
|
||||||
std::size_t total,
|
|
||||||
std::size_t &progress,
|
|
||||||
QtCommon::QtProgressCallback callback);
|
|
||||||
|
|
||||||
bool copyData(QIODevice &inFile,
|
|
||||||
QIODevice &outFile,
|
|
||||||
std::size_t total,
|
|
||||||
std::size_t &progress,
|
|
||||||
QtCommon::QtProgressCallback callback);
|
|
||||||
|
|
||||||
// Extract //
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Extract a zip file and report its progress.
|
|
||||||
* @param fileCompressed Compressed file
|
|
||||||
* @param dir The directory to push the results to
|
|
||||||
* @param callback Callback that takes in two std::size_t (total, progress) and returns false if the current operation should be cancelled.
|
|
||||||
*/
|
|
||||||
QStringList extractDir(QString fileCompressed, QString dir, QtCommon::QtProgressCallback callback = {});
|
|
||||||
|
|
||||||
// Internal //
|
|
||||||
QStringList extractDir(QuaZip &zip, const QString &dir, QtCommon::QtProgressCallback callback);
|
|
||||||
|
|
||||||
bool extractFile(QuaZip *zip,
|
|
||||||
QString fileName,
|
|
||||||
QString fileDest,
|
|
||||||
std::size_t total,
|
|
||||||
std::size_t &progress,
|
|
||||||
QtCommon::QtProgressCallback callback);
|
|
||||||
|
|
||||||
bool removeFile(QStringList listFile);
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,22 +1,17 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#include "qt_common/qt_game_util.h"
|
||||||
#include "qt_content_util.h"
|
#include "qt_content_util.h"
|
||||||
#include "common/fs/fs.h"
|
#include "common/fs/fs.h"
|
||||||
#include "core/hle/service/acc/profile_manager.h"
|
#include "core/hle/service/acc/profile_manager.h"
|
||||||
#include "frontend_common/content_manager.h"
|
#include "frontend_common/content_manager.h"
|
||||||
#include "frontend_common/data_manager.h"
|
|
||||||
#include "frontend_common/firmware_manager.h"
|
#include "frontend_common/firmware_manager.h"
|
||||||
#include "qt_common/qt_common.h"
|
#include "qt_common/qt_common.h"
|
||||||
#include "qt_common/qt_compress.h"
|
|
||||||
#include "qt_common/qt_game_util.h"
|
|
||||||
#include "qt_common/qt_progress_dialog.h"
|
#include "qt_common/qt_progress_dialog.h"
|
||||||
#include "qt_frontend_util.h"
|
#include "qt_frontend_util.h"
|
||||||
|
|
||||||
#include <QFuture>
|
|
||||||
#include <QtConcurrentRun>
|
|
||||||
#include <JlCompress.h>
|
#include <JlCompress.h>
|
||||||
#include <qfuturewatcher.h>
|
|
||||||
|
|
||||||
namespace QtCommon::Content {
|
namespace QtCommon::Content {
|
||||||
|
|
||||||
|
@ -26,10 +21,10 @@ bool CheckGameFirmware(u64 program_id, QObject* parent)
|
||||||
&& !FirmwareManager::CheckFirmwarePresence(*system)) {
|
&& !FirmwareManager::CheckFirmwarePresence(*system)) {
|
||||||
auto result = QtCommon::Frontend::ShowMessage(
|
auto result = QtCommon::Frontend::ShowMessage(
|
||||||
QMessageBox::Warning,
|
QMessageBox::Warning,
|
||||||
tr("Game Requires Firmware"),
|
"Game Requires Firmware",
|
||||||
tr("The game you are trying to launch requires firmware to boot or to get past the "
|
"The game you are trying to launch requires firmware to boot or to get past the "
|
||||||
"opening menu. Please <a href='https://yuzu-mirror.github.io/help/quickstart'>"
|
"opening menu. Please <a href='https://yuzu-mirror.github.io/help/quickstart'>"
|
||||||
"dump and install firmware</a>, or press \"OK\" to launch anyways."),
|
"dump and install firmware</a>, or press \"OK\" to launch anyways.",
|
||||||
QMessageBox::Ok | QMessageBox::Cancel,
|
QMessageBox::Ok | QMessageBox::Cancel,
|
||||||
parent);
|
parent);
|
||||||
|
|
||||||
|
@ -65,8 +60,8 @@ void InstallFirmware(const QString& location, bool recursive)
|
||||||
|
|
||||||
const auto ShowMessage = [&]() {
|
const auto ShowMessage = [&]() {
|
||||||
QtCommon::Frontend::ShowMessage(icon,
|
QtCommon::Frontend::ShowMessage(icon,
|
||||||
tr(failedTitle),
|
failedTitle,
|
||||||
tr(GetFirmwareInstallResultString(result)));
|
GetFirmwareInstallResultString(result));
|
||||||
};
|
};
|
||||||
|
|
||||||
LOG_INFO(Frontend, "Installing firmware from {}", location.toStdString());
|
LOG_INFO(Frontend, "Installing firmware from {}", location.toStdString());
|
||||||
|
@ -130,8 +125,8 @@ void InstallFirmware(const QString& location, bool recursive)
|
||||||
i++;
|
i++;
|
||||||
auto firmware_src_vfile = vfs->OpenFile(firmware_src_path.generic_string(),
|
auto firmware_src_vfile = vfs->OpenFile(firmware_src_path.generic_string(),
|
||||||
FileSys::OpenMode::Read);
|
FileSys::OpenMode::Read);
|
||||||
auto firmware_dst_vfile = firmware_vdir->CreateFileRelative(
|
auto firmware_dst_vfile = firmware_vdir
|
||||||
firmware_src_path.filename().string());
|
->CreateFileRelative(firmware_src_path.filename().string());
|
||||||
|
|
||||||
if (!VfsRawCopy(firmware_src_vfile, firmware_dst_vfile)) {
|
if (!VfsRawCopy(firmware_src_vfile, firmware_dst_vfile)) {
|
||||||
LOG_ERROR(Frontend,
|
LOG_ERROR(Frontend,
|
||||||
|
@ -173,9 +168,9 @@ void InstallFirmware(const QString& location, bool recursive)
|
||||||
const auto failed_names = QString::fromStdString(
|
const auto failed_names = QString::fromStdString(
|
||||||
fmt::format("{}", fmt::join(results, "\n")));
|
fmt::format("{}", fmt::join(results, "\n")));
|
||||||
progress.close();
|
progress.close();
|
||||||
QtCommon::Frontend::Critical(
|
QtCommon::Frontend::Critical(tr("Firmware integrity verification failed!"),
|
||||||
tr("Firmware integrity verification failed!"),
|
tr("Verification failed for the following files:\n\n%1")
|
||||||
tr("Verification failed for the following files:\n\n%1").arg(failed_names));
|
.arg(failed_names));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,10 +181,10 @@ void InstallFirmware(const QString& location, bool recursive)
|
||||||
const std::string display_version(firmware_data.display_version.data());
|
const std::string display_version(firmware_data.display_version.data());
|
||||||
|
|
||||||
result = FirmwareInstallResult::Success;
|
result = FirmwareInstallResult::Success;
|
||||||
QtCommon::Frontend::Information(
|
QtCommon::Frontend::Information(rootObject,
|
||||||
rootObject,
|
tr(successTitle),
|
||||||
tr(successTitle),
|
tr(GetFirmwareInstallResultString(result))
|
||||||
tr(GetFirmwareInstallResultString(result)).arg(QString::fromStdString(display_version)));
|
.arg(QString::fromStdString(display_version)));
|
||||||
}
|
}
|
||||||
|
|
||||||
QString UnzipFirmwareToTmp(const QString& location)
|
QString UnzipFirmwareToTmp(const QString& location)
|
||||||
|
@ -198,7 +193,7 @@ QString UnzipFirmwareToTmp(const QString& location)
|
||||||
fs::path tmp{fs::temp_directory_path()};
|
fs::path tmp{fs::temp_directory_path()};
|
||||||
|
|
||||||
if (!fs::create_directories(tmp / "eden" / "firmware")) {
|
if (!fs::create_directories(tmp / "eden" / "firmware")) {
|
||||||
return QString();
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
tmp /= "eden";
|
tmp /= "eden";
|
||||||
|
@ -210,7 +205,7 @@ QString UnzipFirmwareToTmp(const QString& location)
|
||||||
|
|
||||||
QStringList result = JlCompress::extractDir(&zip, qCacheDir);
|
QStringList result = JlCompress::extractDir(&zip, qCacheDir);
|
||||||
if (result.isEmpty()) {
|
if (result.isEmpty()) {
|
||||||
return QString();
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
return qCacheDir;
|
return qCacheDir;
|
||||||
|
@ -269,8 +264,9 @@ void InstallKeys()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
FirmwareManager::KeyInstallResult result
|
FirmwareManager::KeyInstallResult result = FirmwareManager::InstallKeys(key_source_location
|
||||||
= FirmwareManager::InstallKeys(key_source_location.toStdString(), "keys");
|
.toStdString(),
|
||||||
|
"keys");
|
||||||
|
|
||||||
system->GetFileSystemController().CreateFactories(*QtCommon::vfs);
|
system->GetFileSystemController().CreateFactories(*QtCommon::vfs);
|
||||||
|
|
||||||
|
@ -286,14 +282,9 @@ void InstallKeys()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VerifyInstalledContents()
|
void VerifyInstalledContents() {
|
||||||
{
|
|
||||||
// Initialize a progress dialog.
|
// Initialize a progress dialog.
|
||||||
QtCommon::Frontend::QtProgressDialog progress(tr("Verifying integrity..."),
|
QtCommon::Frontend::QtProgressDialog progress(tr("Verifying integrity..."), tr("Cancel"), 0, 100, QtCommon::rootObject);
|
||||||
tr("Cancel"),
|
|
||||||
0,
|
|
||||||
100,
|
|
||||||
QtCommon::rootObject);
|
|
||||||
progress.setWindowModality(Qt::WindowModal);
|
progress.setWindowModality(Qt::WindowModal);
|
||||||
progress.setMinimumDuration(100);
|
progress.setMinimumDuration(100);
|
||||||
progress.setAutoClose(false);
|
progress.setAutoClose(false);
|
||||||
|
@ -305,17 +296,16 @@ void VerifyInstalledContents()
|
||||||
return progress.wasCanceled();
|
return progress.wasCanceled();
|
||||||
};
|
};
|
||||||
|
|
||||||
const std::vector<std::string> result
|
const std::vector<std::string> result =
|
||||||
= ContentManager::VerifyInstalledContents(*QtCommon::system,
|
ContentManager::VerifyInstalledContents(*QtCommon::system, *QtCommon::provider, QtProgressCallback);
|
||||||
*QtCommon::provider,
|
|
||||||
QtProgressCallback);
|
|
||||||
progress.close();
|
progress.close();
|
||||||
|
|
||||||
if (result.empty()) {
|
if (result.empty()) {
|
||||||
QtCommon::Frontend::Information(tr("Integrity verification succeeded!"),
|
QtCommon::Frontend::Information(tr("Integrity verification succeeded!"),
|
||||||
tr("The operation completed successfully."));
|
tr("The operation completed successfully."));
|
||||||
} else {
|
} else {
|
||||||
const auto failed_names = QString::fromStdString(fmt::format("{}", fmt::join(result, "\n")));
|
const auto failed_names =
|
||||||
|
QString::fromStdString(fmt::format("{}", fmt::join(result, "\n")));
|
||||||
QtCommon::Frontend::Critical(
|
QtCommon::Frontend::Critical(
|
||||||
tr("Integrity verification failed!"),
|
tr("Integrity verification failed!"),
|
||||||
tr("Verification failed for the following files:\n\n%1").arg(failed_names));
|
tr("Verification failed for the following files:\n\n%1").arg(failed_names));
|
||||||
|
@ -342,7 +332,7 @@ void FixProfiles()
|
||||||
qorphaned.reserve(8 * 33);
|
qorphaned.reserve(8 * 33);
|
||||||
|
|
||||||
for (const std::string& s : orphaned) {
|
for (const std::string& s : orphaned) {
|
||||||
qorphaned = qorphaned % QStringLiteral("\n") % QString::fromStdString(s);
|
qorphaned += "\n" + QString::fromStdString(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
QtCommon::Frontend::Critical(
|
QtCommon::Frontend::Critical(
|
||||||
|
@ -358,183 +348,4 @@ void FixProfiles()
|
||||||
QtCommon::Game::OpenSaveFolder();
|
QtCommon::Game::OpenSaveFolder();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClearDataDir(FrontendCommon::DataManager::DataDir dir, const std::string& user_id)
|
|
||||||
{
|
|
||||||
auto result = QtCommon::Frontend::Warning(tr("Really clear data?"),
|
|
||||||
tr("Important data may be lost!"),
|
|
||||||
QMessageBox::Yes | QMessageBox::No);
|
|
||||||
|
|
||||||
if (result != QMessageBox::Yes)
|
|
||||||
return;
|
|
||||||
|
|
||||||
result = QtCommon::Frontend::Warning(
|
|
||||||
tr("Are you REALLY sure?"),
|
|
||||||
tr("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, user_id);
|
|
||||||
|
|
||||||
dialog.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExportDataDir(FrontendCommon::DataManager::DataDir data_dir,
|
|
||||||
const std::string& user_id,
|
|
||||||
std::function<void()> callback)
|
|
||||||
{
|
|
||||||
using namespace QtCommon::Frontend;
|
|
||||||
const std::string dir = FrontendCommon::DataManager::GetDataDir(data_dir, user_id);
|
|
||||||
|
|
||||||
const QString zip_dump_location = GetSaveFileName(tr("Select Export Location"),
|
|
||||||
QStringLiteral("export.zip"),
|
|
||||||
tr("Zipped Archives (*.zip)"));
|
|
||||||
|
|
||||||
if (zip_dump_location.isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
QtProgressDialog* progress = new QtProgressDialog(
|
|
||||||
tr("Exporting data. This may take a while..."), tr("Cancel"), 0, 100, rootObject);
|
|
||||||
|
|
||||||
progress->setWindowTitle(tr("Exporting"));
|
|
||||||
progress->setWindowModality(Qt::WindowModal);
|
|
||||||
progress->setMinimumDuration(100);
|
|
||||||
progress->setAutoClose(false);
|
|
||||||
progress->setAutoReset(false);
|
|
||||||
progress->show();
|
|
||||||
|
|
||||||
QGuiApplication::processEvents();
|
|
||||||
|
|
||||||
auto progress_callback = [=](size_t total_size, size_t processed_size) {
|
|
||||||
QMetaObject::invokeMethod(progress,
|
|
||||||
&QtProgressDialog::setValue,
|
|
||||||
static_cast<int>((processed_size * 100) / total_size));
|
|
||||||
|
|
||||||
return !progress->wasCanceled();
|
|
||||||
};
|
|
||||||
|
|
||||||
QFuture<bool> future = QtConcurrent::run([=]() {
|
|
||||||
return QtCommon::Compress::compressDir(zip_dump_location,
|
|
||||||
QString::fromStdString(dir),
|
|
||||||
JlCompress::Options(),
|
|
||||||
progress_callback);
|
|
||||||
});
|
|
||||||
|
|
||||||
QFutureWatcher<bool>* watcher = new QFutureWatcher<bool>(rootObject);
|
|
||||||
|
|
||||||
QObject::connect(watcher, &QFutureWatcher<bool>::finished, rootObject, [=]() {
|
|
||||||
progress->close();
|
|
||||||
|
|
||||||
if (watcher->result()) {
|
|
||||||
Information(tr("Exported Successfully"), tr("Data was exported successfully."));
|
|
||||||
} else if (progress->wasCanceled()) {
|
|
||||||
Information(tr("Export Cancelled"), tr("Export was cancelled by the user."));
|
|
||||||
} else {
|
|
||||||
Critical(
|
|
||||||
tr("Export Failed"),
|
|
||||||
tr("Ensure you have write permissions on the targeted directory and try again."));
|
|
||||||
}
|
|
||||||
|
|
||||||
progress->deleteLater();
|
|
||||||
watcher->deleteLater();
|
|
||||||
if (callback)
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
|
|
||||||
watcher->setFuture(future);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImportDataDir(FrontendCommon::DataManager::DataDir data_dir,
|
|
||||||
const std::string& user_id,
|
|
||||||
std::function<void()> callback)
|
|
||||||
{
|
|
||||||
const std::string dir = FrontendCommon::DataManager::GetDataDir(data_dir, user_id);
|
|
||||||
|
|
||||||
using namespace QtCommon::Frontend;
|
|
||||||
|
|
||||||
const QString zip_dump_location = GetOpenFileName(tr("Select Import Location"),
|
|
||||||
{},
|
|
||||||
tr("Zipped Archives (*.zip)"));
|
|
||||||
|
|
||||||
if (zip_dump_location.isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
StandardButton button = Warning(
|
|
||||||
tr("Import Warning"),
|
|
||||||
tr("All previous data in this directory will be deleted. Are you sure you wish to "
|
|
||||||
"proceed?"),
|
|
||||||
StandardButton::Yes | StandardButton::No);
|
|
||||||
|
|
||||||
if (button != QMessageBox::Yes)
|
|
||||||
return;
|
|
||||||
|
|
||||||
QtProgressDialog* progress = new QtProgressDialog(
|
|
||||||
tr("Importing data. This may take a while..."), tr("Cancel"), 0, 100, rootObject);
|
|
||||||
|
|
||||||
progress->setWindowTitle(tr("Importing"));
|
|
||||||
progress->setWindowModality(Qt::WindowModal);
|
|
||||||
progress->setMinimumDuration(100);
|
|
||||||
progress->setAutoClose(false);
|
|
||||||
progress->setAutoReset(false);
|
|
||||||
progress->show();
|
|
||||||
progress->setValue(0);
|
|
||||||
|
|
||||||
QGuiApplication::processEvents();
|
|
||||||
|
|
||||||
// to prevent GUI mangling we have to run this in a thread as well
|
|
||||||
QFuture<bool> delete_future = QtConcurrent::run([=]() {
|
|
||||||
FrontendCommon::DataManager::ClearDir(data_dir, user_id);
|
|
||||||
return !progress->wasCanceled();
|
|
||||||
});
|
|
||||||
|
|
||||||
QFutureWatcher<bool>* delete_watcher = new QFutureWatcher<bool>(rootObject);
|
|
||||||
delete_watcher->setFuture(delete_future);
|
|
||||||
|
|
||||||
QObject::connect(delete_watcher, &QFutureWatcher<bool>::finished, rootObject, [=]() {
|
|
||||||
auto progress_callback = [=](size_t total_size, size_t processed_size) {
|
|
||||||
QMetaObject::invokeMethod(progress,
|
|
||||||
&QtProgressDialog::setValue,
|
|
||||||
static_cast<int>((processed_size * 100) / total_size));
|
|
||||||
|
|
||||||
return !progress->wasCanceled();
|
|
||||||
};
|
|
||||||
|
|
||||||
QFuture<bool> future = QtConcurrent::run([=]() {
|
|
||||||
return !QtCommon::Compress::extractDir(zip_dump_location,
|
|
||||||
QString::fromStdString(dir),
|
|
||||||
progress_callback)
|
|
||||||
.empty();
|
|
||||||
});
|
|
||||||
|
|
||||||
QFutureWatcher<bool>* watcher = new QFutureWatcher<bool>(rootObject);
|
|
||||||
|
|
||||||
QObject::connect(watcher, &QFutureWatcher<bool>::finished, rootObject, [=]() {
|
|
||||||
progress->close();
|
|
||||||
|
|
||||||
// this sucks
|
|
||||||
if (watcher->result()) {
|
|
||||||
Information(tr("Imported Successfully"), tr("Data was imported successfully."));
|
|
||||||
} else if (progress->wasCanceled()) {
|
|
||||||
Information(tr("Import Cancelled"), tr("Import was cancelled by the user."));
|
|
||||||
} else {
|
|
||||||
Critical(tr("Import Failed"),
|
|
||||||
tr("Ensure you have read permissions on the targeted directory and try "
|
|
||||||
"again."));
|
|
||||||
}
|
|
||||||
|
|
||||||
progress->deleteLater();
|
|
||||||
watcher->deleteLater();
|
|
||||||
if (callback)
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
|
|
||||||
watcher->setFuture(future);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace QtCommon::Content
|
} // namespace QtCommon::Content
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "frontend_common/data_manager.h"
|
|
||||||
|
|
||||||
namespace QtCommon::Content {
|
namespace QtCommon::Content {
|
||||||
|
|
||||||
|
@ -47,10 +46,6 @@ void InstallKeys();
|
||||||
void VerifyGameContents(const std::string &game_path);
|
void VerifyGameContents(const std::string &game_path);
|
||||||
void VerifyInstalledContents();
|
void VerifyInstalledContents();
|
||||||
|
|
||||||
void ClearDataDir(FrontendCommon::DataManager::DataDir dir, const std::string &user_id = "");
|
|
||||||
void ExportDataDir(FrontendCommon::DataManager::DataDir dir, const std::string &user_id = "", std::function<void()> callback = {});
|
|
||||||
void ImportDataDir(FrontendCommon::DataManager::DataDir dir, const std::string &user_id = "", std::function<void()> callback = {});
|
|
||||||
|
|
||||||
// Profiles //
|
// Profiles //
|
||||||
void FixProfiles();
|
void FixProfiles();
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,15 +32,4 @@ const QString GetOpenFileName(const QString &title,
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString GetSaveFileName(const QString &title,
|
|
||||||
const QString &dir,
|
|
||||||
const QString &filter,
|
|
||||||
QString *selectedFilter,
|
|
||||||
Options options)
|
|
||||||
{
|
|
||||||
#ifdef YUZU_QT_WIDGETS
|
|
||||||
return QFileDialog::getSaveFileName((QWidget *) rootObject, title, dir, filter, selectedFilter, options);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace QtCommon::Frontend
|
} // namespace QtCommon::Frontend
|
||||||
|
|
|
@ -97,10 +97,10 @@ Q_ENUM_NS(Icon)
|
||||||
|
|
||||||
// TODO(crueter) widgets-less impl, choices et al.
|
// TODO(crueter) widgets-less impl, choices et al.
|
||||||
StandardButton ShowMessage(Icon icon,
|
StandardButton ShowMessage(Icon icon,
|
||||||
const QString &title,
|
const QString &title,
|
||||||
const QString &text,
|
const QString &text,
|
||||||
StandardButtons buttons = StandardButton::NoButton,
|
StandardButtons buttons = StandardButton::NoButton,
|
||||||
QObject *parent = nullptr);
|
QObject *parent = nullptr);
|
||||||
|
|
||||||
#define UTIL_OVERRIDES(level) \
|
#define UTIL_OVERRIDES(level) \
|
||||||
inline StandardButton level(QObject *parent, \
|
inline StandardButton level(QObject *parent, \
|
||||||
|
@ -110,6 +110,21 @@ StandardButton ShowMessage(Icon icon,
|
||||||
{ \
|
{ \
|
||||||
return ShowMessage(Icon::level, title, text, buttons, parent); \
|
return ShowMessage(Icon::level, title, text, buttons, parent); \
|
||||||
} \
|
} \
|
||||||
|
inline StandardButton level(QObject *parent, \
|
||||||
|
const char *title, \
|
||||||
|
const char *text, \
|
||||||
|
StandardButtons buttons \
|
||||||
|
= StandardButton::Ok) \
|
||||||
|
{ \
|
||||||
|
return ShowMessage(Icon::level, tr(title), tr(text), buttons, parent); \
|
||||||
|
} \
|
||||||
|
inline StandardButton level(const char *title, \
|
||||||
|
const char *text, \
|
||||||
|
StandardButtons buttons \
|
||||||
|
= StandardButton::Ok) \
|
||||||
|
{ \
|
||||||
|
return ShowMessage(Icon::level, tr(title), tr(text), buttons, rootObject); \
|
||||||
|
} \
|
||||||
inline StandardButton level(const QString title, \
|
inline StandardButton level(const QString title, \
|
||||||
const QString &text, \
|
const QString &text, \
|
||||||
StandardButtons buttons \
|
StandardButtons buttons \
|
||||||
|
@ -129,11 +144,5 @@ const QString GetOpenFileName(const QString &title,
|
||||||
QString *selectedFilter = nullptr,
|
QString *selectedFilter = nullptr,
|
||||||
Options options = Options());
|
Options options = Options());
|
||||||
|
|
||||||
const QString GetSaveFileName(const QString &title,
|
|
||||||
const QString &dir,
|
|
||||||
const QString &filter,
|
|
||||||
QString *selectedFilter = nullptr,
|
|
||||||
Options options = Options());
|
|
||||||
|
|
||||||
} // namespace QtCommon::Frontend
|
} // namespace QtCommon::Frontend
|
||||||
#endif // QT_FRONTEND_UTIL_H
|
#endif // QT_FRONTEND_UTIL_H
|
||||||
|
|
|
@ -220,8 +220,8 @@ void RemoveBaseContent(u64 program_id, InstalledEntryType type)
|
||||||
program_id);
|
program_id);
|
||||||
if (res) {
|
if (res) {
|
||||||
QtCommon::Frontend::Information(rootObject,
|
QtCommon::Frontend::Information(rootObject,
|
||||||
tr("Successfully Removed"),
|
"Successfully Removed",
|
||||||
tr("Successfully removed the installed base game."));
|
"Successfully removed the installed base game.");
|
||||||
} else {
|
} else {
|
||||||
QtCommon::Frontend::Warning(
|
QtCommon::Frontend::Warning(
|
||||||
rootObject,
|
rootObject,
|
||||||
|
@ -235,8 +235,8 @@ void RemoveUpdateContent(u64 program_id, InstalledEntryType type)
|
||||||
const auto res = ContentManager::RemoveUpdate(system->GetFileSystemController(), program_id);
|
const auto res = ContentManager::RemoveUpdate(system->GetFileSystemController(), program_id);
|
||||||
if (res) {
|
if (res) {
|
||||||
QtCommon::Frontend::Information(rootObject,
|
QtCommon::Frontend::Information(rootObject,
|
||||||
tr("Successfully Removed"),
|
"Successfully Removed",
|
||||||
tr("Successfully removed the installed update."));
|
"Successfully removed the installed update.");
|
||||||
} else {
|
} else {
|
||||||
QtCommon::Frontend::Warning(rootObject,
|
QtCommon::Frontend::Warning(rootObject,
|
||||||
GetGameListErrorRemoving(type),
|
GetGameListErrorRemoving(type),
|
||||||
|
|
|
@ -17,12 +17,7 @@ bool OpenShaderCache(u64 program_id, QObject *parent)
|
||||||
const auto shader_cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir);
|
const auto shader_cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir);
|
||||||
const auto shader_cache_folder_path{shader_cache_dir / fmt::format("{:016x}", program_id)};
|
const auto shader_cache_folder_path{shader_cache_dir / fmt::format("{:016x}", program_id)};
|
||||||
if (!Common::FS::CreateDirs(shader_cache_folder_path)) {
|
if (!Common::FS::CreateDirs(shader_cache_folder_path)) {
|
||||||
QtCommon::Frontend::ShowMessage(QMessageBox::Warning,
|
QtCommon::Frontend::ShowMessage(QMessageBox::Warning, "Error Opening Shader Cache", "Failed to create or open shader cache for this title, ensure your app data directory has write permissions.", QMessageBox::Ok, parent);
|
||||||
tr("Error Opening Shader Cache"),
|
|
||||||
tr("Failed to create or open shader cache for this title, "
|
|
||||||
"ensure your app data directory has write permissions."),
|
|
||||||
QMessageBox::Ok,
|
|
||||||
parent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto shader_path_string{Common::FS::PathToUTF8String(shader_cache_folder_path)};
|
const auto shader_path_string{Common::FS::PathToUTF8String(shader_cache_folder_path)};
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#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, "Contains game save data. DO NOT REMOVE UNLESS YOU KNOW WHAT YOU'RE DOING!"},
|
|
||||||
{ShadersTooltip, "Contains Vulkan and OpenGL pipeline caches. Generally safe to remove."},
|
|
||||||
{UserNandTooltip, "Contains updates and DLC for games."},
|
|
||||||
{SysNandTooltip, "Contains firmware and applet data."},
|
|
||||||
{ModsTooltip, "Contains game mods, patches, and cheats."},
|
|
||||||
};
|
|
||||||
|
|
||||||
static inline const QString Lookup(StringKey key)
|
|
||||||
{
|
|
||||||
return QString::fromStdString(strings.at(key).data());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -386,11 +386,9 @@ void BufferCache<P>::BindHostComputeBuffers() {
|
||||||
template <class P>
|
template <class P>
|
||||||
void BufferCache<P>::SetUniformBuffersState(const std::array<u32, NUM_STAGES>& mask,
|
void BufferCache<P>::SetUniformBuffersState(const std::array<u32, NUM_STAGES>& mask,
|
||||||
const UniformBufferSizes* sizes) {
|
const UniformBufferSizes* sizes) {
|
||||||
if constexpr (HAS_PERSISTENT_UNIFORM_BUFFER_BINDINGS) {
|
if (channel_state->enabled_uniform_buffer_masks != mask) {
|
||||||
if (channel_state->enabled_uniform_buffer_masks != mask) {
|
channel_state->fast_bound_uniform_buffers.fill(0);
|
||||||
if constexpr (IS_OPENGL) {
|
if constexpr (HAS_PERSISTENT_UNIFORM_BUFFER_BINDINGS) {
|
||||||
channel_state->fast_bound_uniform_buffers.fill(0);
|
|
||||||
}
|
|
||||||
channel_state->dirty_uniform_buffers.fill(~u32{0});
|
channel_state->dirty_uniform_buffers.fill(~u32{0});
|
||||||
channel_state->uniform_buffer_binding_sizes.fill({});
|
channel_state->uniform_buffer_binding_sizes.fill({});
|
||||||
}
|
}
|
||||||
|
@ -806,7 +804,7 @@ void BufferCache<P>::BindHostGraphicsUniformBuffer(size_t stage, u32 index, u32
|
||||||
channel_state->uniform_buffer_binding_sizes[stage][binding_index] != size;
|
channel_state->uniform_buffer_binding_sizes[stage][binding_index] != size;
|
||||||
if (should_fast_bind) {
|
if (should_fast_bind) {
|
||||||
// We only have to bind when the currently bound buffer is not the fast version
|
// We only have to bind when the currently bound buffer is not the fast version
|
||||||
channel_state->fast_bound_uniform_buffers[stage] |= 1U << binding_index;
|
channel_state->fast_bound_uniform_buffers[stage] |= 1u << binding_index;
|
||||||
channel_state->uniform_buffer_binding_sizes[stage][binding_index] = size;
|
channel_state->uniform_buffer_binding_sizes[stage][binding_index] = size;
|
||||||
runtime.BindFastUniformBuffer(stage, binding_index, size);
|
runtime.BindFastUniformBuffer(stage, binding_index, size);
|
||||||
}
|
}
|
||||||
|
@ -815,10 +813,8 @@ void BufferCache<P>::BindHostGraphicsUniformBuffer(size_t stage, u32 index, u32
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if constexpr (IS_OPENGL) {
|
channel_state->fast_bound_uniform_buffers[stage] |= 1u << binding_index;
|
||||||
channel_state->fast_bound_uniform_buffers[stage] |= 1U << binding_index;
|
channel_state->uniform_buffer_binding_sizes[stage][binding_index] = size;
|
||||||
channel_state->uniform_buffer_binding_sizes[stage][binding_index] = size;
|
|
||||||
}
|
|
||||||
// Stream buffer path to avoid stalling on non-Nvidia drivers or Vulkan
|
// Stream buffer path to avoid stalling on non-Nvidia drivers or Vulkan
|
||||||
const std::span<u8> span = runtime.BindMappedUniformBuffer(stage, binding_index, size);
|
const std::span<u8> span = runtime.BindMappedUniformBuffer(stage, binding_index, size);
|
||||||
device_memory.ReadBlockUnsafe(device_addr, span.data(), size);
|
device_memory.ReadBlockUnsafe(device_addr, span.data(), size);
|
||||||
|
@ -839,9 +835,6 @@ void BufferCache<P>::BindHostGraphicsUniformBuffer(size_t stage, u32 index, u32
|
||||||
}
|
}
|
||||||
const u32 offset = buffer.Offset(device_addr);
|
const u32 offset = buffer.Offset(device_addr);
|
||||||
if constexpr (IS_OPENGL) {
|
if constexpr (IS_OPENGL) {
|
||||||
// Fast buffer will be unbound
|
|
||||||
channel_state->fast_bound_uniform_buffers[stage] &= ~(1U << binding_index);
|
|
||||||
|
|
||||||
// Mark the index as dirty if offset doesn't match
|
// Mark the index as dirty if offset doesn't match
|
||||||
const bool is_copy_bind = offset != 0 && !runtime.SupportsNonZeroUniformOffset();
|
const bool is_copy_bind = offset != 0 && !runtime.SupportsNonZeroUniformOffset();
|
||||||
channel_state->dirty_uniform_buffers[stage] |= (is_copy_bind ? 1U : 0U) << index;
|
channel_state->dirty_uniform_buffers[stage] |= (is_copy_bind ? 1U : 0U) << index;
|
||||||
|
@ -855,6 +848,7 @@ void BufferCache<P>::BindHostGraphicsUniformBuffer(size_t stage, u32 index, u32
|
||||||
} else {
|
} else {
|
||||||
runtime.BindUniformBuffer(buffer, offset, size);
|
runtime.BindUniformBuffer(buffer, offset, size);
|
||||||
}
|
}
|
||||||
|
channel_state->fast_bound_uniform_buffers[stage] &= ~(1u << binding_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class P>
|
template <class P>
|
||||||
|
@ -1789,12 +1783,7 @@ std::span<u8> BufferCache<P>::ImmediateBuffer(size_t wanted_capacity) {
|
||||||
|
|
||||||
template <class P>
|
template <class P>
|
||||||
bool BufferCache<P>::HasFastUniformBufferBound(size_t stage, u32 binding_index) const noexcept {
|
bool BufferCache<P>::HasFastUniformBufferBound(size_t stage, u32 binding_index) const noexcept {
|
||||||
if constexpr (IS_OPENGL) {
|
return ((channel_state->fast_bound_uniform_buffers[stage] >> binding_index) & 1u) != 0;
|
||||||
return ((channel_state->fast_bound_uniform_buffers[stage] >> binding_index) & 1) != 0;
|
|
||||||
} else {
|
|
||||||
// Only OpenGL has fast uniform buffers
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class P>
|
template <class P>
|
||||||
|
|
|
@ -54,6 +54,8 @@ constexpr u32 NUM_STORAGE_BUFFERS = 16;
|
||||||
constexpr u32 NUM_TEXTURE_BUFFERS = 32;
|
constexpr u32 NUM_TEXTURE_BUFFERS = 32;
|
||||||
constexpr u32 NUM_STAGES = 5;
|
constexpr u32 NUM_STAGES = 5;
|
||||||
|
|
||||||
|
static_assert(NUM_GRAPHICS_UNIFORM_BUFFERS <= 32, "fast bitmask must fit u32");
|
||||||
|
|
||||||
using UniformBufferSizes = std::array<std::array<u32, NUM_GRAPHICS_UNIFORM_BUFFERS>, NUM_STAGES>;
|
using UniformBufferSizes = std::array<std::array<u32, NUM_GRAPHICS_UNIFORM_BUFFERS>, NUM_STAGES>;
|
||||||
using ComputeUniformBufferSizes = std::array<u32, NUM_COMPUTE_UNIFORM_BUFFERS>;
|
using ComputeUniformBufferSizes = std::array<u32, NUM_COMPUTE_UNIFORM_BUFFERS>;
|
||||||
|
|
||||||
|
@ -137,8 +139,8 @@ public:
|
||||||
u32 written_compute_texture_buffers = 0;
|
u32 written_compute_texture_buffers = 0;
|
||||||
u32 image_compute_texture_buffers = 0;
|
u32 image_compute_texture_buffers = 0;
|
||||||
|
|
||||||
std::array<u32, 16> uniform_cache_hits{};
|
std::array<u32, NUM_GRAPHICS_UNIFORM_BUFFERS> uniform_cache_hits{};
|
||||||
std::array<u32, 16> uniform_cache_shots{};
|
std::array<u32, NUM_GRAPHICS_UNIFORM_BUFFERS> uniform_cache_shots{};
|
||||||
|
|
||||||
u32 uniform_buffer_skip_cache_size = DEFAULT_SKIP_CACHE_SIZE;
|
u32 uniform_buffer_skip_cache_size = DEFAULT_SKIP_CACHE_SIZE;
|
||||||
|
|
||||||
|
|
|
@ -234,9 +234,6 @@ add_executable(yuzu
|
||||||
deps_dialog.cpp
|
deps_dialog.cpp
|
||||||
deps_dialog.h
|
deps_dialog.h
|
||||||
deps_dialog.ui
|
deps_dialog.ui
|
||||||
|
|
||||||
data_dialog.h data_dialog.cpp data_dialog.ui
|
|
||||||
data_widget.ui
|
|
||||||
)
|
)
|
||||||
|
|
||||||
set_target_properties(yuzu PROPERTIES OUTPUT_NAME "eden")
|
set_target_properties(yuzu PROPERTIES OUTPUT_NAME "eden")
|
||||||
|
@ -393,13 +390,32 @@ endif()
|
||||||
|
|
||||||
target_link_libraries(yuzu PRIVATE nlohmann_json::nlohmann_json)
|
target_link_libraries(yuzu PRIVATE nlohmann_json::nlohmann_json)
|
||||||
target_link_libraries(yuzu PRIVATE common core input_common frontend_common network video_core qt_common)
|
target_link_libraries(yuzu PRIVATE common core input_common frontend_common network video_core qt_common)
|
||||||
target_link_libraries(yuzu PRIVATE Boost::headers glad Qt6::Widgets Qt6::Concurrent)
|
target_link_libraries(yuzu PRIVATE Boost::headers glad Qt6::Widgets)
|
||||||
target_link_libraries(yuzu PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads)
|
target_link_libraries(yuzu PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads)
|
||||||
|
|
||||||
if (UNIX AND NOT APPLE)
|
if (UNIX AND NOT APPLE)
|
||||||
target_link_libraries(yuzu PRIVATE Qt6::DBus)
|
target_link_libraries(yuzu PRIVATE Qt6::DBus)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
target_compile_definitions(yuzu PRIVATE
|
||||||
|
# Use QStringBuilder for string concatenation to reduce
|
||||||
|
# the overall number of temporary strings created.
|
||||||
|
QT_USE_QSTRINGBUILDER
|
||||||
|
|
||||||
|
# Disable implicit conversions from/to C strings
|
||||||
|
QT_NO_CAST_FROM_ASCII
|
||||||
|
QT_NO_CAST_TO_ASCII
|
||||||
|
|
||||||
|
# Disable implicit type narrowing in signal/slot connect() calls.
|
||||||
|
QT_NO_NARROWING_CONVERSIONS_IN_CONNECT
|
||||||
|
|
||||||
|
# Disable unsafe overloads of QProcess' start() function.
|
||||||
|
QT_NO_PROCESS_COMBINED_ARGUMENT_START
|
||||||
|
|
||||||
|
# Disable implicit QString->QUrl conversions to enforce use of proper resolving functions.
|
||||||
|
QT_NO_URL_CAST_FROM_STRING
|
||||||
|
)
|
||||||
|
|
||||||
if (YUZU_ENABLE_COMPATIBILITY_REPORTING)
|
if (YUZU_ENABLE_COMPATIBILITY_REPORTING)
|
||||||
target_compile_definitions(yuzu PRIVATE YUZU_ENABLE_COMPATIBILITY_REPORTING)
|
target_compile_definitions(yuzu PRIVATE YUZU_ENABLE_COMPATIBILITY_REPORTING)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -1,13 +1,10 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: 2017 Citra Emulator Project
|
// SPDX-FileCopyrightText: 2017 Citra Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include <QButtonGroup>
|
#include <QButtonGroup>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <qtconcurrentrun.h>
|
#include <QtConcurrent/qtconcurrentrun.h>
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "ui_compatdb.h"
|
#include "ui_compatdb.h"
|
||||||
#include "yuzu/compatdb.h"
|
#include "yuzu/compatdb.h"
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
#include <QRegExpValidator>
|
#include <QRegExpValidator>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <QtConcurrentRun>
|
#include <QtConcurrent/QtConcurrentRun>
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
#include "ui_configure_web.h"
|
#include "ui_configure_web.h"
|
||||||
#include "qt_common/uisettings.h"
|
#include "qt_common/uisettings.h"
|
||||||
|
|
|
@ -1,165 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#include "data_dialog.h"
|
|
||||||
#include "core/hle/service/acc/profile_manager.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 <QFileDialog>
|
|
||||||
#include <QFutureWatcher>
|
|
||||||
#include <QProgressDialog>
|
|
||||||
#include <QtConcurrentRun>
|
|
||||||
|
|
||||||
#include <core/frontend/applets/profile_select.h>
|
|
||||||
|
|
||||||
#include <applets/qt_profile_select.h>
|
|
||||||
|
|
||||||
DataDialog::DataDialog(QWidget *parent)
|
|
||||||
: QDialog(parent)
|
|
||||||
, ui(std::make_unique<Ui::DataDialog>())
|
|
||||||
{
|
|
||||||
ui->setupUi(this);
|
|
||||||
|
|
||||||
// TODO: Should we make this a single widget that pulls data from a model?
|
|
||||||
#define WIDGET(name) \
|
|
||||||
ui->page->addWidget(new DataWidget(FrontendCommon::DataManager::DataDir::name, \
|
|
||||||
QtCommon::StringLookup::name##Tooltip, \
|
|
||||||
this));
|
|
||||||
|
|
||||||
WIDGET(Saves)
|
|
||||||
WIDGET(Shaders)
|
|
||||||
WIDGET(UserNand)
|
|
||||||
WIDGET(SysNand)
|
|
||||||
WIDGET(Mods)
|
|
||||||
|
|
||||||
#undef WIDGET
|
|
||||||
|
|
||||||
connect(ui->labels, &QListWidget::itemSelectionChanged, this, [this]() {
|
|
||||||
const auto items = ui->labels->selectedItems();
|
|
||||||
if (items.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ui->page->setCurrentIndex(ui->labels->row(items[0]));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
DataDialog::~DataDialog() = default;
|
|
||||||
|
|
||||||
DataWidget::DataWidget(FrontendCommon::DataManager::DataDir data_dir,
|
|
||||||
QtCommon::StringLookup::StringKey tooltip,
|
|
||||||
QWidget *parent)
|
|
||||||
: QWidget(parent)
|
|
||||||
, ui(std::make_unique<Ui::DataWidget>())
|
|
||||||
, m_dir(data_dir)
|
|
||||||
{
|
|
||||||
ui->setupUi(this);
|
|
||||||
|
|
||||||
ui->tooltip->setText(QtCommon::StringLookup::Lookup(tooltip));
|
|
||||||
|
|
||||||
ui->clear->setIcon(QIcon::fromTheme(QStringLiteral("user-trash")));
|
|
||||||
ui->open->setIcon(QIcon::fromTheme(QStringLiteral("folder")));
|
|
||||||
ui->upload->setIcon(QIcon::fromTheme(QStringLiteral("upload")));
|
|
||||||
ui->download->setIcon(QIcon::fromTheme(QStringLiteral("download")));
|
|
||||||
|
|
||||||
connect(ui->clear, &QPushButton::clicked, this, &DataWidget::clear);
|
|
||||||
connect(ui->open, &QPushButton::clicked, this, &DataWidget::open);
|
|
||||||
connect(ui->upload, &QPushButton::clicked, this, &DataWidget::upload);
|
|
||||||
connect(ui->download, &QPushButton::clicked, this, &DataWidget::download);
|
|
||||||
|
|
||||||
scan();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DataWidget::clear()
|
|
||||||
{
|
|
||||||
std::string user_id{};
|
|
||||||
if (m_dir == FrontendCommon::DataManager::DataDir::Saves) {
|
|
||||||
user_id = selectProfile();
|
|
||||||
}
|
|
||||||
QtCommon::Content::ClearDataDir(m_dir, user_id);
|
|
||||||
scan();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DataWidget::open()
|
|
||||||
{
|
|
||||||
std::string user_id{};
|
|
||||||
if (m_dir == FrontendCommon::DataManager::DataDir::Saves) {
|
|
||||||
user_id = selectProfile();
|
|
||||||
}
|
|
||||||
QDesktopServices::openUrl(QUrl::fromLocalFile(
|
|
||||||
QString::fromStdString(FrontendCommon::DataManager::GetDataDir(m_dir, user_id))));
|
|
||||||
}
|
|
||||||
|
|
||||||
void DataWidget::upload()
|
|
||||||
{
|
|
||||||
std::string user_id{};
|
|
||||||
if (m_dir == FrontendCommon::DataManager::DataDir::Saves) {
|
|
||||||
user_id = selectProfile();
|
|
||||||
}
|
|
||||||
QtCommon::Content::ExportDataDir(m_dir, user_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DataWidget::download()
|
|
||||||
{
|
|
||||||
std::string user_id{};
|
|
||||||
if (m_dir == FrontendCommon::DataManager::DataDir::Saves) {
|
|
||||||
user_id = selectProfile();
|
|
||||||
}
|
|
||||||
QtCommon::Content::ImportDataDir(m_dir, user_id, std::bind(&DataWidget::scan, this));
|
|
||||||
}
|
|
||||||
|
|
||||||
void DataWidget::scan() {
|
|
||||||
ui->size->setText(tr("Calculating..."));
|
|
||||||
|
|
||||||
QFutureWatcher<u64> *watcher = new QFutureWatcher<u64>(this);
|
|
||||||
|
|
||||||
connect(watcher, &QFutureWatcher<u64>::finished, this, [=, this]() {
|
|
||||||
u64 size = watcher->result();
|
|
||||||
ui->size->setText(
|
|
||||||
QString::fromStdString(FrontendCommon::DataManager::ReadableBytesSize(size)));
|
|
||||||
watcher->deleteLater();
|
|
||||||
});
|
|
||||||
|
|
||||||
watcher->setFuture(
|
|
||||||
QtConcurrent::run([this]() { return FrontendCommon::DataManager::DataDirSize(m_dir); }));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string DataWidget::selectProfile()
|
|
||||||
{
|
|
||||||
const auto select_profile = [this] {
|
|
||||||
const Core::Frontend::ProfileSelectParameters parameters{
|
|
||||||
.mode = Service::AM::Frontend::UiMode::UserSelector,
|
|
||||||
.invalid_uid_list = {},
|
|
||||||
.display_options = {},
|
|
||||||
.purpose = Service::AM::Frontend::UserSelectionPurpose::General,
|
|
||||||
};
|
|
||||||
QtProfileSelectionDialog dialog(*QtCommon::system, this, parameters);
|
|
||||||
dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint
|
|
||||||
| Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint);
|
|
||||||
dialog.setWindowModality(Qt::WindowModal);
|
|
||||||
|
|
||||||
if (dialog.exec() == QDialog::Rejected) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return dialog.GetIndex();
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto index = select_profile();
|
|
||||||
if (index == -1) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto uuid = QtCommon::system->GetProfileManager().GetUser(static_cast<std::size_t>(index));
|
|
||||||
ASSERT(uuid);
|
|
||||||
|
|
||||||
const auto user_id = uuid->AsU128();
|
|
||||||
|
|
||||||
return fmt::format("{:016X}{:016X}", user_id[1], user_id[0]);
|
|
||||||
}
|
|
|
@ -1,52 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#ifndef DATA_DIALOG_H
|
|
||||||
#define DATA_DIALOG_H
|
|
||||||
|
|
||||||
#include <QDialog>
|
|
||||||
#include "frontend_common/data_manager.h"
|
|
||||||
#include "qt_common/qt_string_lookup.h"
|
|
||||||
|
|
||||||
#include "ui_data_widget.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 DataWidget : public QWidget
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
explicit DataWidget(FrontendCommon::DataManager::DataDir data_dir,
|
|
||||||
QtCommon::StringLookup::StringKey tooltip,
|
|
||||||
QWidget *parent = nullptr);
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void clear();
|
|
||||||
void open();
|
|
||||||
void upload();
|
|
||||||
void download();
|
|
||||||
|
|
||||||
void scan();
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::unique_ptr<Ui::DataWidget> ui;
|
|
||||||
FrontendCommon::DataManager::DataDir m_dir;
|
|
||||||
|
|
||||||
std::string selectProfile();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // DATA_DIALOG_H
|
|
|
@ -1,148 +0,0 @@
|
||||||
<?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>480</width>
|
|
||||||
<height>320</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>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,1">
|
|
||||||
<item>
|
|
||||||
<widget class="QListWidget" name="labels">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>Saves</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>Shaders</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>UserNAND</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>SysNAND</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>Mods</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QStackedWidget" name="page">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>275</width>
|
|
||||||
<height>200</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="currentIndex">
|
|
||||||
<number>-1</number>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
|
||||||
<property name="leftMargin">
|
|
||||||
<number>10</number>
|
|
||||||
</property>
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="label">
|
|
||||||
<property name="text">
|
|
||||||
<string>Deleting ANY data is IRREVERSABLE!</string>
|
|
||||||
</property>
|
|
||||||
</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>
|
|
||||||
</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>
|
|
|
@ -1,205 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<ui version="4.0">
|
|
||||||
<class>DataWidget</class>
|
|
||||||
<widget class="QWidget" name="DataWidget">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>275</width>
|
|
||||||
<height>200</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="windowTitle">
|
|
||||||
<string>Form</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
|
||||||
<item row="0" column="0">
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="3,2">
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="tooltip">
|
|
||||||
<property name="text">
|
|
||||||
<string>Tooltip</string>
|
|
||||||
</property>
|
|
||||||
<property name="alignment">
|
|
||||||
<set>Qt::AlignmentFlag::AlignCenter</set>
|
|
||||||
</property>
|
|
||||||
<property name="wordWrap">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="size">
|
|
||||||
<property name="font">
|
|
||||||
<font>
|
|
||||||
<pointsize>10</pointsize>
|
|
||||||
<bold>true</bold>
|
|
||||||
</font>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string notr="true">Size</string>
|
|
||||||
</property>
|
|
||||||
<property name="alignment">
|
|
||||||
<set>Qt::AlignmentFlag::AlignCenter</set>
|
|
||||||
</property>
|
|
||||||
<property name="wordWrap">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="0">
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="open">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
|
||||||
<horstretch>1</horstretch>
|
|
||||||
<verstretch>1</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>52</width>
|
|
||||||
<height>47</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>Open with your system file manager</string>
|
|
||||||
</property>
|
|
||||||
<property name="styleSheet">
|
|
||||||
<string notr="true">QPushButton {
|
|
||||||
max-width: 50px;
|
|
||||||
max-height: 45px;
|
|
||||||
min-width: 50px;
|
|
||||||
min-height: 45px;
|
|
||||||
}</string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<property name="iconSize">
|
|
||||||
<size>
|
|
||||||
<width>28</width>
|
|
||||||
<height>28</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="clear">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
|
||||||
<horstretch>1</horstretch>
|
|
||||||
<verstretch>1</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>52</width>
|
|
||||||
<height>47</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>Delete all data in this directory. THIS IS 100% IRREVERSABLE!</string>
|
|
||||||
</property>
|
|
||||||
<property name="styleSheet">
|
|
||||||
<string notr="true">QPushButton {
|
|
||||||
max-width: 50px;
|
|
||||||
max-height: 45px;
|
|
||||||
min-width: 50px;
|
|
||||||
min-height: 45px;
|
|
||||||
}</string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<property name="iconSize">
|
|
||||||
<size>
|
|
||||||
<width>28</width>
|
|
||||||
<height>28</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="upload">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
|
||||||
<horstretch>1</horstretch>
|
|
||||||
<verstretch>1</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>52</width>
|
|
||||||
<height>47</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>Export all data in this directory. This may take a while!</string>
|
|
||||||
</property>
|
|
||||||
<property name="styleSheet">
|
|
||||||
<string notr="true">QPushButton {
|
|
||||||
max-width: 50px;
|
|
||||||
max-height: 45px;
|
|
||||||
min-width: 50px;
|
|
||||||
min-height: 45px;
|
|
||||||
}</string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<property name="iconSize">
|
|
||||||
<size>
|
|
||||||
<width>28</width>
|
|
||||||
<height>28</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="download">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
|
||||||
<horstretch>1</horstretch>
|
|
||||||
<verstretch>1</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>52</width>
|
|
||||||
<height>47</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>Import data for this directory. This may take a while, and will delete ALL EXISTING DATA!</string>
|
|
||||||
</property>
|
|
||||||
<property name="styleSheet">
|
|
||||||
<string notr="true">QPushButton {
|
|
||||||
max-width: 50px;
|
|
||||||
max-height: 45px;
|
|
||||||
min-width: 50px;
|
|
||||||
min-height: 45px;
|
|
||||||
}</string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<property name="iconSize">
|
|
||||||
<size>
|
|
||||||
<width>28</width>
|
|
||||||
<height>28</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
<resources/>
|
|
||||||
<connections/>
|
|
||||||
</ui>
|
|
|
@ -156,7 +156,6 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
|
||||||
#include "yuzu/debugger/console.h"
|
#include "yuzu/debugger/console.h"
|
||||||
#include "yuzu/debugger/controller.h"
|
#include "yuzu/debugger/controller.h"
|
||||||
#include "yuzu/debugger/wait_tree.h"
|
#include "yuzu/debugger/wait_tree.h"
|
||||||
#include "yuzu/data_dialog.h"
|
|
||||||
#include "yuzu/deps_dialog.h"
|
#include "yuzu/deps_dialog.h"
|
||||||
#include "yuzu/discord.h"
|
#include "yuzu/discord.h"
|
||||||
#include "yuzu/game_list.h"
|
#include "yuzu/game_list.h"
|
||||||
|
@ -1706,7 +1705,6 @@ void GMainWindow::ConnectMenuEvents() {
|
||||||
connect_menu(ui->action_Install_Keys, &GMainWindow::OnInstallDecryptionKeys);
|
connect_menu(ui->action_Install_Keys, &GMainWindow::OnInstallDecryptionKeys);
|
||||||
connect_menu(ui->action_About, &GMainWindow::OnAbout);
|
connect_menu(ui->action_About, &GMainWindow::OnAbout);
|
||||||
connect_menu(ui->action_Eden_Dependencies, &GMainWindow::OnEdenDependencies);
|
connect_menu(ui->action_Eden_Dependencies, &GMainWindow::OnEdenDependencies);
|
||||||
connect_menu(ui->action_Data_Manager, &GMainWindow::OnDataDialog);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GMainWindow::UpdateMenuState() {
|
void GMainWindow::UpdateMenuState() {
|
||||||
|
@ -2408,6 +2406,7 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target
|
||||||
|
|
||||||
ASSERT_MSG(has_user_save != has_device_save, "Game uses both user and device savedata?");
|
ASSERT_MSG(has_user_save != has_device_save, "Game uses both user and device savedata?");
|
||||||
|
|
||||||
|
// TODO(alekpop): It returns the wrong user
|
||||||
switch (target) {
|
switch (target) {
|
||||||
case GameListOpenTarget::SaveData: {
|
case GameListOpenTarget::SaveData: {
|
||||||
open_target = tr("Save Data");
|
open_target = tr("Save Data");
|
||||||
|
@ -2793,7 +2792,6 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga
|
||||||
}
|
}
|
||||||
|
|
||||||
void GMainWindow::OnGameListOpenDirectory(const QString& directory) {
|
void GMainWindow::OnGameListOpenDirectory(const QString& directory) {
|
||||||
// TODO(crueter): QtCommon
|
|
||||||
std::filesystem::path fs_path;
|
std::filesystem::path fs_path;
|
||||||
if (directory == QStringLiteral("SDMC")) {
|
if (directory == QStringLiteral("SDMC")) {
|
||||||
fs_path =
|
fs_path =
|
||||||
|
@ -3936,15 +3934,6 @@ void GMainWindow::OnEdenDependencies() {
|
||||||
depsDialog.exec();
|
depsDialog.exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GMainWindow::OnDataDialog() {
|
|
||||||
DataDialog dataDialog(this);
|
|
||||||
dataDialog.exec();
|
|
||||||
|
|
||||||
// refresh stuff in case it was cleared
|
|
||||||
OnGameListRefresh();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void GMainWindow::OnToggleFilterBar() {
|
void GMainWindow::OnToggleFilterBar() {
|
||||||
game_list->SetFilterVisible(ui->action_Show_Filter_Bar->isChecked());
|
game_list->SetFilterVisible(ui->action_Show_Filter_Bar->isChecked());
|
||||||
if (ui->action_Show_Filter_Bar->isChecked()) {
|
if (ui->action_Show_Filter_Bar->isChecked()) {
|
||||||
|
@ -4485,15 +4474,11 @@ void GMainWindow::SetFirmwareVersion() {
|
||||||
|
|
||||||
if (result.IsError() || !CheckFirmwarePresence()) {
|
if (result.IsError() || !CheckFirmwarePresence()) {
|
||||||
LOG_INFO(Frontend, "Installed firmware: No firmware available");
|
LOG_INFO(Frontend, "Installed firmware: No firmware available");
|
||||||
ui->menu_Applets->setEnabled(false);
|
|
||||||
ui->menu_Create_Shortcuts->setEnabled(false);
|
|
||||||
firmware_label->setVisible(false);
|
firmware_label->setVisible(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
firmware_label->setVisible(true);
|
firmware_label->setVisible(true);
|
||||||
ui->menu_Applets->setEnabled(true);
|
|
||||||
ui->menu_Create_Shortcuts->setEnabled(true);
|
|
||||||
|
|
||||||
const std::string display_version(firmware_data.display_version.data());
|
const std::string display_version(firmware_data.display_version.data());
|
||||||
const std::string display_title(firmware_data.display_title.data());
|
const std::string display_title(firmware_data.display_title.data());
|
||||||
|
|
|
@ -387,7 +387,6 @@ private slots:
|
||||||
void OnInstallDecryptionKeys();
|
void OnInstallDecryptionKeys();
|
||||||
void OnAbout();
|
void OnAbout();
|
||||||
void OnEdenDependencies();
|
void OnEdenDependencies();
|
||||||
void OnDataDialog();
|
|
||||||
void OnToggleFilterBar();
|
void OnToggleFilterBar();
|
||||||
void OnToggleStatusBar();
|
void OnToggleStatusBar();
|
||||||
void OnGameListRefresh();
|
void OnGameListRefresh();
|
||||||
|
|
|
@ -158,23 +158,13 @@
|
||||||
</property>
|
</property>
|
||||||
<widget class="QMenu" name="menu_cabinet_applet">
|
<widget class="QMenu" name="menu_cabinet_applet">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>Am&iibo</string>
|
<string>&Amiibo</string>
|
||||||
</property>
|
</property>
|
||||||
<addaction name="action_Load_Cabinet_Nickname_Owner"/>
|
<addaction name="action_Load_Cabinet_Nickname_Owner"/>
|
||||||
<addaction name="action_Load_Cabinet_Eraser"/>
|
<addaction name="action_Load_Cabinet_Eraser"/>
|
||||||
<addaction name="action_Load_Cabinet_Restorer"/>
|
<addaction name="action_Load_Cabinet_Restorer"/>
|
||||||
<addaction name="action_Load_Cabinet_Formatter"/>
|
<addaction name="action_Load_Cabinet_Formatter"/>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QMenu" name="menu_Applets">
|
|
||||||
<property name="title">
|
|
||||||
<string>&Applets</string>
|
|
||||||
</property>
|
|
||||||
<addaction name="action_Load_Home_Menu"/>
|
|
||||||
<addaction name="action_Load_Album"/>
|
|
||||||
<addaction name="action_Load_Mii_Edit"/>
|
|
||||||
<addaction name="action_Open_Controller_Menu"/>
|
|
||||||
<addaction name="action_Open_Setup"/>
|
|
||||||
</widget>
|
|
||||||
<widget class="QMenu" name="menuTAS">
|
<widget class="QMenu" name="menuTAS">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>&TAS</string>
|
<string>&TAS</string>
|
||||||
|
@ -194,7 +184,7 @@
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QMenu" name="menuInstall_Firmware">
|
<widget class="QMenu" name="menuInstall_Firmware">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>Install &Firmware</string>
|
<string>Install Firmware</string>
|
||||||
</property>
|
</property>
|
||||||
<addaction name="action_Firmware_From_Folder"/>
|
<addaction name="action_Firmware_From_Folder"/>
|
||||||
<addaction name="action_Firmware_From_ZIP"/>
|
<addaction name="action_Firmware_From_ZIP"/>
|
||||||
|
@ -202,10 +192,13 @@
|
||||||
<addaction name="action_Install_Keys"/>
|
<addaction name="action_Install_Keys"/>
|
||||||
<addaction name="menuInstall_Firmware"/>
|
<addaction name="menuInstall_Firmware"/>
|
||||||
<addaction name="action_Verify_installed_contents"/>
|
<addaction name="action_Verify_installed_contents"/>
|
||||||
<addaction name="action_Data_Manager"/>
|
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="menu_cabinet_applet"/>
|
<addaction name="menu_cabinet_applet"/>
|
||||||
<addaction name="menu_Applets"/>
|
<addaction name="action_Load_Album"/>
|
||||||
|
<addaction name="action_Load_Mii_Edit"/>
|
||||||
|
<addaction name="action_Open_Controller_Menu"/>
|
||||||
|
<addaction name="action_Load_Home_Menu"/>
|
||||||
|
<addaction name="action_Open_Setup"/>
|
||||||
<addaction name="menu_Create_Shortcuts"/>
|
<addaction name="menu_Create_Shortcuts"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="action_Capture_Screenshot"/>
|
<addaction name="action_Capture_Screenshot"/>
|
||||||
|
@ -504,12 +497,12 @@
|
||||||
</action>
|
</action>
|
||||||
<action name="action_Install_Keys">
|
<action name="action_Install_Keys">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Install Decryption &Keys</string>
|
<string>Install Decryption Keys</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="action_Load_Home_Menu">
|
<action name="action_Load_Home_Menu">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Open &Home Menu</string>
|
<string>Open Home Menu</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="action_Discord">
|
<action name="action_Discord">
|
||||||
|
@ -600,11 +593,6 @@
|
||||||
<string>&Eden Dependencies</string>
|
<string>&Eden Dependencies</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="action_Data_Manager">
|
|
||||||
<property name="text">
|
|
||||||
<string>&Data Manager</string>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
</widget>
|
</widget>
|
||||||
<resources>
|
<resources>
|
||||||
<include location="yuzu.qrc"/>
|
<include location="yuzu.qrc"/>
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
#include <QMetaType>
|
#include <QMetaType>
|
||||||
#include <QTime>
|
#include <QTime>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include <QtConcurrentRun>
|
#include <QtConcurrent/QtConcurrentRun>
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "network/announce_multiplayer_session.h"
|
#include "network/announce_multiplayer_session.h"
|
||||||
#include "ui_chat_room.h"
|
#include "ui_chat_room.h"
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
#include <QLocale>
|
#include <QLocale>
|
||||||
#include <QMetaType>
|
#include <QMetaType>
|
||||||
#include <QTime>
|
#include <QTime>
|
||||||
#include <QtConcurrentRun>
|
#include <QtConcurrent/QtConcurrentRun>
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "network/announce_multiplayer_session.h"
|
#include "network/announce_multiplayer_session.h"
|
||||||
#include "ui_client_room.h"
|
#include "ui_client_room.h"
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
#include <QIntValidator>
|
#include <QIntValidator>
|
||||||
#include <QRegularExpressionValidator>
|
#include <QRegularExpressionValidator>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QtConcurrentRun>
|
#include <QtConcurrent/QtConcurrentRun>
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/internal_network/network_interface.h"
|
#include "core/internal_network/network_interface.h"
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QMetaType>
|
#include <QMetaType>
|
||||||
#include <QTime>
|
#include <QTime>
|
||||||
#include <QtConcurrentRun>
|
#include <QtConcurrent/QtConcurrentRun>
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
#include <QInputDialog>
|
#include <QInputDialog>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QtConcurrentRun>
|
#include <QtConcurrent/QtConcurrentRun>
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
|
|