mirror of
https://github.com/DarkMatterCore/nxdumptool.git
synced 2024-11-22 18:26:39 +00:00
[ci skip] OptionsTab: add option to unmount UMS devices
Uses a SelectListItem element with displayValue set to false to avoid displaying a value string. Furthermore, the default click event callback is replaced to check if any UMS devices are mounted before attempting to display the dropdown menu. Other changes include: * UmsTask: define UmsDeviceVectorEntry. * UmsTask: redefine UmsDeviceVector as a UmsDeviceVectorEntry vector. * UmsTask: migrate UMS device string generation logic from DumpOptionsFrame::UpdateStorages() to UmsTask::PopulateUmsDeviceVector(). * DumpOptionsFrame: simplify UpdateStorages() to reflect the changes made to UmsTask.
This commit is contained in:
parent
7d7f2d58a8
commit
17e0edb61c
9 changed files with 119 additions and 26 deletions
|
@ -91,7 +91,8 @@ namespace nxdt::views
|
||||||
u64 total_sz = 0, free_sz = 0;
|
u64 total_sz = 0, free_sz = 0;
|
||||||
char total_sz_str[64] = {0}, free_sz_str[64] = {0};
|
char total_sz_str[64] = {0}, free_sz_str[64] = {0};
|
||||||
|
|
||||||
const UsbHsFsDevice *cur_ums_device = (i >= ConfigOutputStorage_Count ? &(ums_devices.at(i - ConfigOutputStorage_Count)) : nullptr);
|
const nxdt::tasks::UmsDeviceVectorEntry *ums_device_entry = (i >= ConfigOutputStorage_Count ? &(ums_devices.at(i - ConfigOutputStorage_Count)) : nullptr);
|
||||||
|
const UsbHsFsDevice *cur_ums_device = (ums_device_entry ? ums_device_entry->first : nullptr);
|
||||||
|
|
||||||
sprintf(total_sz_str, "%s/", cur_ums_device ? cur_ums_device->name : DEVOPTAB_SDMC_DEVICE);
|
sprintf(total_sz_str, "%s/", cur_ums_device ? cur_ums_device->name : DEVOPTAB_SDMC_DEVICE);
|
||||||
utilsGetFileSystemStatsByPath(total_sz_str, &total_sz, &free_sz);
|
utilsGetFileSystemStatsByPath(total_sz_str, &total_sz, &free_sz);
|
||||||
|
@ -100,9 +101,7 @@ namespace nxdt::views
|
||||||
|
|
||||||
if (cur_ums_device)
|
if (cur_ums_device)
|
||||||
{
|
{
|
||||||
std::string ums_extra_info = (cur_ums_device->product_name[0] ? (std::string(cur_ums_device->product_name) + ", ") : "");
|
storages.push_back(brls::i18n::getStr("dump_options/output_storage/value_02", ums_device_entry->second, free_sz_str, total_sz_str));
|
||||||
ums_extra_info += fmt::format("LUN {}, FS #{}, {}", cur_ums_device->lun, cur_ums_device->fs_idx, LIBUSBHSFS_FS_TYPE_STR(cur_ums_device->fs_type));
|
|
||||||
storages.push_back(brls::i18n::getStr("dump_options/output_storage/value_02", static_cast<int>(strlen(cur_ums_device->name + 3) - 1), cur_ums_device->name + 3, free_sz_str, total_sz_str, ums_extra_info));
|
|
||||||
} else {
|
} else {
|
||||||
storages.push_back(brls::i18n::getStr("dump_options/output_storage/value_00", free_sz_str, total_sz_str));
|
storages.push_back(brls::i18n::getStr("dump_options/output_storage/value_00", free_sz_str, total_sz_str));
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,9 +73,13 @@ namespace nxdt::views
|
||||||
private:
|
private:
|
||||||
RootView *root_view = nullptr;
|
RootView *root_view = nullptr;
|
||||||
|
|
||||||
|
brls::SelectListItem *unmount_ums_device = nullptr;
|
||||||
|
nxdt::tasks::UmsDeviceVector ums_devices{};
|
||||||
|
nxdt::tasks::UmsEvent::Subscription ums_task_sub;
|
||||||
|
|
||||||
bool display_notification = true;
|
bool display_notification = true;
|
||||||
brls::menu_timer_t notification_timer = 0.0f;
|
brls::menu_timer_t notification_timer = 0.0f;
|
||||||
brls::menu_timer_ctx_entry_t notification_timer_ctx = {0};
|
brls::menu_timer_ctx_entry_t notification_timer_ctx{};
|
||||||
|
|
||||||
void DisplayNotification(const std::string& str);
|
void DisplayNotification(const std::string& str);
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -52,8 +52,9 @@ namespace nxdt::tasks
|
||||||
/* Used to hold pointers to application metadata entries. */
|
/* Used to hold pointers to application metadata entries. */
|
||||||
typedef std::vector<TitleApplicationMetadata*> TitleApplicationMetadataVector;
|
typedef std::vector<TitleApplicationMetadata*> TitleApplicationMetadataVector;
|
||||||
|
|
||||||
/* Used to hold UMS devices. */
|
/* Used to hold information from UMS devices. */
|
||||||
typedef std::vector<UsbHsFsDevice> UmsDeviceVector;
|
typedef std::pair<const UsbHsFsDevice*, std::string> UmsDeviceVectorEntry;
|
||||||
|
typedef std::vector<UmsDeviceVectorEntry> UmsDeviceVector;
|
||||||
|
|
||||||
/* Custom event types. */
|
/* Custom event types. */
|
||||||
typedef brls::Event<const StatusInfoData&> StatusInfoEvent;
|
typedef brls::Event<const StatusInfoData&> StatusInfoEvent;
|
||||||
|
@ -133,7 +134,11 @@ namespace nxdt::tasks
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
UmsEvent ums_event;
|
UmsEvent ums_event;
|
||||||
UmsDeviceVector ums_devices{};
|
|
||||||
|
UsbHsFsDevice *ums_devices = nullptr;
|
||||||
|
u32 ums_devices_count = 0;
|
||||||
|
|
||||||
|
UmsDeviceVector ums_devices_vector{};
|
||||||
|
|
||||||
void PopulateUmsDeviceVector(void);
|
void PopulateUmsDeviceVector(void);
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit ed6f2ef76a136b0f77ce599e8401dbdf6bd6d11a
|
Subproject commit e5cbe0d97c32d1102a6ea253ed68a3a8ecfdc3a9
|
|
@ -8,8 +8,8 @@
|
||||||
"label": "Output storage",
|
"label": "Output storage",
|
||||||
"description": "Storage where the dumped data will be written to. Changing it will automatically update the output filename to better suit the output filesystem limitations.\nUsing a connected USB host requires a libusb-based driver, as well as the Python host script. For more information, please visit \"{0}\".",
|
"description": "Storage where the dumped data will be written to. Changing it will automatically update the output filename to better suit the output filesystem limitations.\nUsing a connected USB host requires a libusb-based driver, as well as the Python host script. For more information, please visit \"{0}\".",
|
||||||
"value_00": "SD card ({0} free / {1} total)",
|
"value_00": "SD card ({0} free / {1} total)",
|
||||||
"value_01": "USB host",
|
"value_01": "USB host (PC)",
|
||||||
"value_02": "USB Mass Storage {1:.{0}} ({2} free / {3} total) ({4})"
|
"value_02": "{0} ({1} free / {2} total)"
|
||||||
},
|
},
|
||||||
|
|
||||||
"prepend_key_area": {
|
"prepend_key_area": {
|
||||||
|
|
|
@ -13,6 +13,11 @@
|
||||||
"value_01": "ID and version only"
|
"value_01": "ID and version only"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"unmount_ums_device": {
|
||||||
|
"label": "Unmount USB Mass Storage device",
|
||||||
|
"description": "Safely unmount any USB Mass Storage devices that are currently connected and mounted by {0}.\n\nIf a UMS device has more than one mounted volume, selecting a single one will unmount all volumes from that device.\n\nUMS devices are always safely unmounted at exit."
|
||||||
|
},
|
||||||
|
|
||||||
"update_nswdb_xml": {
|
"update_nswdb_xml": {
|
||||||
"label": "Update NSWDB XML",
|
"label": "Update NSWDB XML",
|
||||||
"description": "Retrieves the latest NSWDB XML, which can be optionally used to validate checksums from gamecard dumps. Requires Internet connectivity."
|
"description": "Retrieves the latest NSWDB XML, which can be optionally used to validate checksums from gamecard dumps. Requires Internet connectivity."
|
||||||
|
@ -35,6 +40,9 @@
|
||||||
},
|
},
|
||||||
|
|
||||||
"notifications": {
|
"notifications": {
|
||||||
|
"no_ums_devices": "No USB Mass Storage devices available.",
|
||||||
|
"ums_device_unmount_success": "USB Mass Storage device successfully unmounted!",
|
||||||
|
"ums_device_unmount_failure": "Failed to unmount USB Mass Storage device!",
|
||||||
"no_internet_connection": "Internet connection unavailable. Unable to update.",
|
"no_internet_connection": "Internet connection unavailable. Unable to update.",
|
||||||
"update_failed": "Update failed! Check the logfile for more info.",
|
"update_failed": "Update failed! Check the logfile for more info.",
|
||||||
"nswdb_xml_updated": "NSWDB XML successfully updated!",
|
"nswdb_xml_updated": "NSWDB XML successfully updated!",
|
||||||
|
|
|
@ -277,7 +277,7 @@ namespace nxdt::views
|
||||||
brls::ListItem *dump_initial_data = new brls::ListItem("gamecard_tab/list/dump_initial_data/label"_i18n, "gamecard_tab/list/dump_initial_data/description"_i18n);
|
brls::ListItem *dump_initial_data = new brls::ListItem("gamecard_tab/list/dump_initial_data/label"_i18n, "gamecard_tab/list/dump_initial_data/description"_i18n);
|
||||||
this->list->addView(dump_initial_data);
|
this->list->addView(dump_initial_data);
|
||||||
|
|
||||||
brls::ListItem *dump_certificate = new brls::ListItem("gamecard_tab/list/dump_certificate/label"_i18n, brls::i18n::getStr("gamecard_tab/list/dump_certificate/description", GAMECARD_CERTIFICATE_OFFSET / GAMECARD_PAGE_SIZE));
|
brls::ListItem *dump_certificate = new brls::ListItem("gamecard_tab/list/dump_certificate/label"_i18n, i18n::getStr("gamecard_tab/list/dump_certificate/description", GAMECARD_CERTIFICATE_OFFSET / GAMECARD_PAGE_SIZE));
|
||||||
this->list->addView(dump_certificate);
|
this->list->addView(dump_certificate);
|
||||||
|
|
||||||
brls::ListItem *dump_card_id_set = new brls::ListItem("gamecard_tab/list/dump_card_id_set/label"_i18n, "gamecard_tab/list/dump_card_id_set/description"_i18n);
|
brls::ListItem *dump_card_id_set = new brls::ListItem("gamecard_tab/list/dump_card_id_set/label"_i18n, "gamecard_tab/list/dump_card_id_set/description"_i18n);
|
||||||
|
@ -286,7 +286,7 @@ namespace nxdt::views
|
||||||
brls::ListItem *dump_card_uid = new brls::ListItem("gamecard_tab/list/dump_card_uid/label"_i18n, "gamecard_tab/list/dump_card_uid/description"_i18n);
|
brls::ListItem *dump_card_uid = new brls::ListItem("gamecard_tab/list/dump_card_uid/label"_i18n, "gamecard_tab/list/dump_card_uid/description"_i18n);
|
||||||
this->list->addView(dump_card_uid);
|
this->list->addView(dump_card_uid);
|
||||||
|
|
||||||
brls::ListItem *dump_header = new brls::ListItem("gamecard_tab/list/dump_header/label"_i18n, brls::i18n::getStr("gamecard_tab/list/dump_header/description", 0));
|
brls::ListItem *dump_header = new brls::ListItem("gamecard_tab/list/dump_header/label"_i18n, i18n::getStr("gamecard_tab/list/dump_header/description", 0));
|
||||||
this->list->addView(dump_header);
|
this->list->addView(dump_header);
|
||||||
|
|
||||||
brls::ListItem *dump_plaintext_cardinfo = new brls::ListItem("gamecard_tab/list/dump_plaintext_cardinfo/label"_i18n, "gamecard_tab/list/dump_plaintext_cardinfo/description"_i18n);
|
brls::ListItem *dump_plaintext_cardinfo = new brls::ListItem("gamecard_tab/list/dump_plaintext_cardinfo/label"_i18n, "gamecard_tab/list/dump_plaintext_cardinfo/description"_i18n);
|
||||||
|
|
|
@ -317,6 +317,62 @@ namespace nxdt::views
|
||||||
|
|
||||||
this->addView(naming_convention);
|
this->addView(naming_convention);
|
||||||
|
|
||||||
|
/* Unmount UMS devices. */
|
||||||
|
/* We will replace its default click event with a new one that will: */
|
||||||
|
/* 1. Check if any UMS devices are available before displaying the dropdown and display a notification if there are none. */
|
||||||
|
/* 2. Generate the string vector required by the dropdown. */
|
||||||
|
/* 3. Initialize the dropdown and pass a custom callback that will take care of unmounting the selected device. */
|
||||||
|
this->unmount_ums_device = new brls::SelectListItem("options_tab/unmount_ums_device/label"_i18n, { "dummy" }, 0,
|
||||||
|
i18n::getStr("options_tab/unmount_ums_device/description"_i18n, APP_TITLE), false);
|
||||||
|
|
||||||
|
this->unmount_ums_device->getClickEvent()->unsubscribeAll();
|
||||||
|
|
||||||
|
this->unmount_ums_device->getClickEvent()->subscribe([this](brls::View* view) {
|
||||||
|
if (this->ums_devices.empty())
|
||||||
|
{
|
||||||
|
/* Display a notification if we haven't mounted any UMS devices at all. */
|
||||||
|
this->DisplayNotification("options_tab/notifications/no_ums_devices"_i18n);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generate values vector for the dropdown. */
|
||||||
|
std::vector<std::string> values{};
|
||||||
|
for(nxdt::tasks::UmsDeviceVectorEntry ums_device_entry : this->ums_devices) values.push_back(ums_device_entry.second);
|
||||||
|
|
||||||
|
/* Display dropdown. */
|
||||||
|
brls::Dropdown::open(this->unmount_ums_device->getLabel(), values, [this](int idx) {
|
||||||
|
/* Make sure the current value isn't out of bounds. */
|
||||||
|
if (idx < 0 || idx >= static_cast<int>(this->ums_devices.size())) return;
|
||||||
|
|
||||||
|
/* Unmount UMS device. */
|
||||||
|
if (umsUnmountDevice(this->ums_devices.at(idx).first))
|
||||||
|
{
|
||||||
|
this->DisplayNotification("options_tab/notifications/ums_device_unmount_success"_i18n);
|
||||||
|
} else {
|
||||||
|
this->DisplayNotification("options_tab/notifications/ums_device_unmount_failure"_i18n);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/* Update UMS devices vector. */
|
||||||
|
this->ums_devices = this->root_view->GetUmsDevices();
|
||||||
|
|
||||||
|
/* Subscribe to the UMS device event. */
|
||||||
|
this->ums_task_sub = this->root_view->RegisterUmsTaskListener([this](const nxdt::tasks::UmsDeviceVector& ums_devices) {
|
||||||
|
/* Update UMS devices vector. */
|
||||||
|
this->ums_devices = this->root_view->GetUmsDevices();
|
||||||
|
|
||||||
|
/* Generate values vector for the dropdown. */
|
||||||
|
std::vector<std::string> values{};
|
||||||
|
for(nxdt::tasks::UmsDeviceVectorEntry ums_device_entry : this->ums_devices) values.push_back(ums_device_entry.second);
|
||||||
|
|
||||||
|
/* Update SelectListItem values. */
|
||||||
|
/* If the dropdown menu is already being displayed, it'll be reloaded or popped from the view stack, depending on whether the provided vector is empty or not. */
|
||||||
|
this->unmount_ums_device->updateValues(values);
|
||||||
|
});
|
||||||
|
|
||||||
|
this->addView(unmount_ums_device);
|
||||||
|
|
||||||
/* Update NSWDB XML. */
|
/* Update NSWDB XML. */
|
||||||
brls::ListItem *update_nswdb_xml = new brls::ListItem("options_tab/update_nswdb_xml/label"_i18n, "options_tab/update_nswdb_xml/description"_i18n);
|
brls::ListItem *update_nswdb_xml = new brls::ListItem("options_tab/update_nswdb_xml/label"_i18n, "options_tab/update_nswdb_xml/description"_i18n);
|
||||||
|
|
||||||
|
@ -367,6 +423,10 @@ namespace nxdt::views
|
||||||
|
|
||||||
OptionsTab::~OptionsTab(void)
|
OptionsTab::~OptionsTab(void)
|
||||||
{
|
{
|
||||||
|
this->root_view->UnregisterUmsTaskListener(this->ums_task_sub);
|
||||||
|
|
||||||
|
this->ums_devices.clear();
|
||||||
|
|
||||||
brls::menu_timer_kill(&(this->notification_timer));
|
brls::menu_timer_kill(&(this->notification_timer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -212,7 +212,10 @@ namespace nxdt::tasks
|
||||||
UmsTask::~UmsTask(void)
|
UmsTask::~UmsTask(void)
|
||||||
{
|
{
|
||||||
/* Clear UMS device vector. */
|
/* Clear UMS device vector. */
|
||||||
this->ums_devices.clear();
|
this->ums_devices_vector.clear();
|
||||||
|
|
||||||
|
/* Free UMS devices buffer. */
|
||||||
|
if (this->ums_devices) free(this->ums_devices);
|
||||||
|
|
||||||
LOG_MSG_DEBUG("UMS task stopped.");
|
LOG_MSG_DEBUG("UMS task stopped.");
|
||||||
}
|
}
|
||||||
|
@ -230,35 +233,49 @@ namespace nxdt::tasks
|
||||||
this->PopulateUmsDeviceVector();
|
this->PopulateUmsDeviceVector();
|
||||||
|
|
||||||
/* Fire task event. */
|
/* Fire task event. */
|
||||||
this->ums_event.fire(this->ums_devices);
|
this->ums_event.fire(this->ums_devices_vector);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const UmsDeviceVector& UmsTask::GetUmsDevices(void)
|
const UmsDeviceVector& UmsTask::GetUmsDevices(void)
|
||||||
{
|
{
|
||||||
return this->ums_devices;
|
return this->ums_devices_vector;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UmsTask::PopulateUmsDeviceVector(void)
|
void UmsTask::PopulateUmsDeviceVector(void)
|
||||||
{
|
{
|
||||||
UsbHsFsDevice *ums_devices = nullptr;
|
|
||||||
u32 ums_device_count = 0;
|
|
||||||
|
|
||||||
/* Clear UMS device vector. */
|
/* Clear UMS device vector. */
|
||||||
this->ums_devices.clear();
|
this->ums_devices_vector.clear();
|
||||||
|
|
||||||
|
/* Free UMS devices buffer. */
|
||||||
|
if (this->ums_devices) free(this->ums_devices);
|
||||||
|
|
||||||
|
/* Reset UMS devices counter. */
|
||||||
|
this->ums_devices_count = 0;
|
||||||
|
|
||||||
/* Get UMS devices. */
|
/* Get UMS devices. */
|
||||||
ums_devices = umsGetDevices(&ums_device_count);
|
this->ums_devices = umsGetDevices(&(this->ums_devices_count));
|
||||||
if (ums_devices)
|
if (this->ums_devices)
|
||||||
{
|
{
|
||||||
/* Fill UMS device vector. */
|
/* Fill UMS device vector. */
|
||||||
for(u32 i = 0; i < ums_device_count; i++) this->ums_devices.push_back(ums_devices[i]);
|
for(u32 i = 0; i < this->ums_devices_count; i++)
|
||||||
|
{
|
||||||
|
const UsbHsFsDevice *cur_ums_device = &(this->ums_devices[i]);
|
||||||
|
int name_len = static_cast<int>(strlen(cur_ums_device->name) - 1);
|
||||||
|
std::string ums_info{};
|
||||||
|
|
||||||
/* Free UMS devices array. */
|
if (cur_ums_device->product_name[0])
|
||||||
free(ums_devices);
|
{
|
||||||
|
ums_info = fmt::format("{1:.{0}} ({2}, LUN #{3}, FS#{4}, {5})", name_len, cur_ums_device->name, cur_ums_device->product_name, cur_ums_device->lun, cur_ums_device->fs_idx, LIBUSBHSFS_FS_TYPE_STR(cur_ums_device->fs_type));
|
||||||
|
} else {
|
||||||
|
ums_info = fmt::format("{1:.{0}} (LUN #{2}, FS#{3}, {4})", name_len, cur_ums_device->name, cur_ums_device->lun, cur_ums_device->fs_idx, LIBUSBHSFS_FS_TYPE_STR(cur_ums_device->fs_type));
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_MSG_DEBUG("Retrieved info for %u UMS %s.", ums_device_count, ums_device_count == 1 ? "device" : "devices");
|
this->ums_devices_vector.push_back(std::make_pair(cur_ums_device, ums_info));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_MSG_DEBUG("Retrieved info for %u UMS %s.", this->ums_devices_count, this->ums_devices_count == 1 ? "device" : "devices");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* USB host device connection task. */
|
/* USB host device connection task. */
|
||||||
|
|
Loading…
Reference in a new issue