diff --git a/include/download_task.hpp b/include/download_task.hpp index 75ca88d..0d4ad02 100644 --- a/include/download_task.hpp +++ b/include/download_task.hpp @@ -28,23 +28,12 @@ #include "core/nxdt_utils.h" #include "async_task.hpp" +#include "eta_progress_display.hpp" namespace nxdt::tasks { - /* Used to hold download progress info. */ - typedef struct { - /// Fields set by DownloadTask::HttpProgressCallback(). - size_t size; ///< Total download size. - size_t current; ///< Number of bytes downloaded thus far. - int percentage; ///< Progress percentage. - - /// Fields set by DownloadTask::onProgressUpdate(). - double speed; ///< Download speed expressed in bytes per second. - std::string eta; ///< Formatted ETA string. - } DownloadTaskProgress; - /* Custom event type used to push download progress updates. */ - typedef brls::Event DownloadProgressEvent; + typedef brls::Event DownloadProgressEvent; /* Used to hold a buffer + size pair with downloaded data. */ typedef std::pair DownloadDataResult; @@ -54,7 +43,7 @@ namespace nxdt::tasks /* This internal RepeatingTask is guaranteed to work on the UI thread, and it is also automatically unregistered on object destruction. */ /* Progress updates are pushed through a DownloadProgressEvent. Make sure to register all event listeners before executing the task. */ template - class DownloadTask: public AsyncTask + class DownloadTask: public AsyncTask { public: /* Handles task progress updates on the calling thread. */ @@ -90,7 +79,7 @@ namespace nxdt::tasks void onCancelled(const Result& result) override final; void onPostExecute(const Result& result) override final; void onPreExecute(void) override final; - void onProgressUpdate(const DownloadTaskProgress& progress) override final; + void onProgressUpdate(const nxdt::views::EtaProgressInfo& progress) override final; public: DownloadTask(void); @@ -153,7 +142,7 @@ namespace nxdt::tasks NX_IGNORE_ARG(ultotal); NX_IGNORE_ARG(ulnow); - DownloadTaskProgress progress = {0}; + nxdt::views::EtaProgressInfo progress = {0}; DownloadTask* task = static_cast*>(clientp); /* Don't proceed if we're dealing with an invalid task pointer, or if the task has been cancelled. */ @@ -212,7 +201,7 @@ namespace nxdt::tasks } template - void DownloadTask::onProgressUpdate(const DownloadTaskProgress& progress) + void DownloadTask::onProgressUpdate(const nxdt::views::EtaProgressInfo& progress) { AsyncTaskStatus status = this->getStatus(); @@ -235,7 +224,7 @@ namespace nxdt::tasks double speed = (diff_current / diff_time_conv); /* Fill struct. */ - DownloadTaskProgress new_progress = progress; + nxdt::views::EtaProgressInfo new_progress = progress; new_progress.speed = speed; if (progress.size) diff --git a/include/dump_options_frame.hpp b/include/dump_options_frame.hpp index 534f28f..2665867 100644 --- a/include/dump_options_frame.hpp +++ b/include/dump_options_frame.hpp @@ -73,7 +73,7 @@ namespace nxdt::views void UpdateRawFileName(void) { - if (raw_filename) free(this->raw_filename); + if (this->raw_filename) free(this->raw_filename); this->raw_filename = strdup(this->filename_input->getValue().c_str()); } @@ -92,7 +92,7 @@ namespace nxdt::views std::string device_str = (std::string(cur_ums_device.name) + ", "); if (cur_ums_device.product_name[0]) device_str += (std::string(cur_ums_device.product_name) + ", "); device_str += 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"_i18n, device_str)); + storages->push_back(brls::i18n::getStr("dump_options/output_storage/value_02", device_str)); } if (this->output_storage->getSelectedValue() > ConfigOutputStorage_UsbHost) @@ -152,7 +152,7 @@ namespace nxdt::views "dump_options/output_storage/value_00"_i18n, "dump_options/output_storage/value_01"_i18n }, configGetInteger("output_storage"), - brls::i18n::getStr("dump_options/output_storage/description"_i18n, GITHUB_REPOSITORY_URL)); + brls::i18n::getStr("dump_options/output_storage/description", GITHUB_REPOSITORY_URL)); /* Subscribe to SelectListItem's value selected event. */ this->output_storage->getValueSelectedEvent()->subscribe([this](int selected) { @@ -292,7 +292,7 @@ namespace nxdt::views "NSWDB", "No-Intro" }, configGetInteger("gamecard/checksum_lookup_method"), - brls::i18n::getStr("dump_options/checksum_lookup_method/description"_i18n, + brls::i18n::getStr("dump_options/checksum_lookup_method/description", "dump_options/calculate_checksum/label"_i18n, "NSWDB", NSWDB_XML_NAME, "No-Intro")); /* Subscribe to SelectListItem's value selected event. */ diff --git a/include/eta_progress_display.hpp b/include/eta_progress_display.hpp new file mode 100644 index 0000000..388f77f --- /dev/null +++ b/include/eta_progress_display.hpp @@ -0,0 +1,68 @@ +/* + * eta_progress_display.hpp + * + * Copyright (c) 2020-2024, DarkMatterCore . + * + * This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool). + * + * nxdumptool is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * nxdumptool is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#ifndef __ETA_PROGRESS_DISPLAY_HPP__ +#define __ETA_PROGRESS_DISPLAY_HPP__ + +#include + +namespace nxdt::views +{ + /* Used to hold progress info. */ + typedef struct { + size_t size; ///< Total process size. + size_t current; ///< Number of bytes processed thus far. + int percentage; ///< Progress percentage. + double speed; ///< Current speed expressed in bytes per second. + std::string eta; ///< Formatted ETA string. + } EtaProgressInfo; + + /* Used to display the progress of a running task. Shows a progress bar, a spinner, a percentage value, the process speed and an ETA value. */ + class EtaProgressDisplay: public brls::View + { + private: + brls::ProgressDisplay *progress_display = nullptr; + brls::Label *size_lbl = nullptr, *speed_eta_lbl = nullptr; + + std::string GetFormattedSizeString(double size); + + protected: + /* Set class as non-copyable and non-moveable. */ + NON_COPYABLE(EtaProgressDisplay); + NON_MOVEABLE(EtaProgressDisplay); + + void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, brls::Style* style, brls::FrameContext* ctx) override; + void layout(NVGcontext* vg, brls::Style* style, brls::FontStash* stash) override; + + public: + EtaProgressDisplay(void); + ~EtaProgressDisplay(void); + + void setProgress(const EtaProgressInfo& progress); + + void willAppear(bool resetState = false) override; + void willDisappear(bool resetState = false) override; + }; +} + +#endif /* __ETA_PROGRESS_DISPLAY_HPP__ */ diff --git a/include/options_tab.hpp b/include/options_tab.hpp index 8704a94..3094afa 100644 --- a/include/options_tab.hpp +++ b/include/options_tab.hpp @@ -27,32 +27,10 @@ #include #include "root_view.hpp" +#include "eta_progress_display.hpp" namespace nxdt::views { - /* Used in OptionsTabUpdateFileDialog and OptionsTabUpdateApplicationFrame to display the update progress. */ - class OptionsTabUpdateProgress: public brls::View - { - private: - brls::ProgressDisplay *progress_display = nullptr; - brls::Label *size_lbl = nullptr, *speed_eta_lbl = nullptr; - - std::string GetFormattedSizeString(double size); - - protected: - void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, brls::Style* style, brls::FrameContext* ctx) override; - void layout(NVGcontext* vg, brls::Style* style, brls::FontStash* stash) override; - - public: - OptionsTabUpdateProgress(void); - ~OptionsTabUpdateProgress(void); - - void SetProgress(const nxdt::tasks::DownloadTaskProgress& progress); - - void willAppear(bool resetState = false) override; - void willDisappear(bool resetState = false) override; - }; - /* Update file dialog. */ class OptionsTabUpdateFileDialog: public brls::Dialog { @@ -73,9 +51,9 @@ namespace nxdt::views size_t json_buf_size = 0; UtilsGitHubReleaseJsonData json_data = {0}; - brls::Label *wait_lbl = nullptr; /// First stage. - brls::List *changelog_list = nullptr; /// Second stage. - OptionsTabUpdateProgress *update_progress = nullptr; /// Third stage. + brls::Label *wait_lbl = nullptr; /// First stage. + brls::List *changelog_list = nullptr; /// Second stage. + EtaProgressDisplay *update_progress = nullptr; /// Third stage. nxdt::tasks::DownloadFileTask nro_task; diff --git a/source/eta_progress_display.cpp b/source/eta_progress_display.cpp new file mode 100644 index 0000000..33932fe --- /dev/null +++ b/source/eta_progress_display.cpp @@ -0,0 +1,133 @@ +/* + * eta_progress_display.cpp + * + * Copyright (c) 2020-2024, DarkMatterCore . + * + * This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool). + * + * nxdumptool is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * nxdumptool is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +namespace i18n = brls::i18n; /* For getStr(). */ +using namespace i18n::literals; /* For _i18n. */ + +namespace nxdt::views +{ + EtaProgressDisplay::EtaProgressDisplay(void) + { + this->progress_display = new brls::ProgressDisplay(); + this->progress_display->setParent(this); + + this->size_lbl = new brls::Label(brls::LabelStyle::MEDIUM, "", false); + this->size_lbl->setVerticalAlign(NVG_ALIGN_BOTTOM); + this->size_lbl->setParent(this); + + this->speed_eta_lbl = new brls::Label(brls::LabelStyle::MEDIUM, "", false); + this->speed_eta_lbl->setVerticalAlign(NVG_ALIGN_TOP); + this->speed_eta_lbl->setParent(this); + } + + EtaProgressDisplay::~EtaProgressDisplay(void) + { + delete this->progress_display; + delete this->size_lbl; + delete this->speed_eta_lbl; + } + + void EtaProgressDisplay::draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, brls::Style* style, brls::FrameContext* ctx) + { + /* Progress display. */ + this->progress_display->frame(ctx); + + /* Size label. */ + this->size_lbl->frame(ctx); + + /* Speed / ETA label. */ + this->speed_eta_lbl->frame(ctx); + } + + void EtaProgressDisplay::layout(NVGcontext* vg, brls::Style* style, brls::FontStash* stash) + { + unsigned elem_width = roundf(static_cast(this->width) * 0.90f); + + /* Progress display. */ + this->progress_display->setBoundaries( + this->x + (this->width - elem_width) / 2, + this->y + (this->height - style->CrashFrame.buttonHeight) / 2, + elem_width, + style->CrashFrame.buttonHeight); + + this->progress_display->invalidate(true); + + /* Size label. */ + this->size_lbl->setWidth(elem_width); + this->size_lbl->invalidate(true); + + this->size_lbl->setBoundaries( + this->x + (this->width - this->size_lbl->getWidth()) / 2, + this->progress_display->getY() - this->progress_display->getHeight() / 8, + this->size_lbl->getWidth(), + this->size_lbl->getHeight()); + + /* Speed / ETA label. */ + this->speed_eta_lbl->setWidth(elem_width); + this->speed_eta_lbl->invalidate(true); + + this->speed_eta_lbl->setBoundaries( + this->x + (this->width - this->speed_eta_lbl->getWidth()) / 2, + this->progress_display->getY() + this->progress_display->getHeight() + this->progress_display->getHeight() / 8, + this->speed_eta_lbl->getWidth(), + this->speed_eta_lbl->getHeight()); + } + + void EtaProgressDisplay::setProgress(const EtaProgressInfo& progress) + { + /* Update progress percentage. */ + this->progress_display->setProgress(progress.percentage, 100); + + /* Update size string. */ + this->size_lbl->setText(fmt::format("{} / {}", this->GetFormattedSizeString(static_cast(progress.current)), \ + progress.size ? this->GetFormattedSizeString(static_cast(progress.size)) : "?")); + + /* Update speed / ETA string. */ + if (progress.eta.length()) + { + this->speed_eta_lbl->setText(fmt::format("{}/s - ETA: {}", this->GetFormattedSizeString(progress.speed), progress.eta)); + } else { + this->speed_eta_lbl->setText(fmt::format("{}/s", this->GetFormattedSizeString(progress.speed))); + } + + this->invalidate(); + } + + void EtaProgressDisplay::willAppear(bool resetState) + { + this->progress_display->willAppear(resetState); + } + + void EtaProgressDisplay::willDisappear(bool resetState) + { + this->progress_display->willDisappear(resetState); + } + + std::string EtaProgressDisplay::GetFormattedSizeString(double size) + { + char strbuf[0x40] = {0}; + utilsGenerateFormattedSizeString(size, strbuf, sizeof(strbuf)); + return std::string(strbuf); + } +} diff --git a/source/gamecard_tab.cpp b/source/gamecard_tab.cpp index e6ec89c..acd61f6 100644 --- a/source/gamecard_tab.cpp +++ b/source/gamecard_tab.cpp @@ -268,7 +268,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); this->list->addView(dump_initial_data); - brls::ListItem *dump_certificate = new brls::ListItem("gamecard_tab/list/dump_certificate/label"_i18n, fmt::format("gamecard_tab/list/dump_certificate/description"_i18n, GAMECARD_CERTIFICATE_OFFSET / GAMECARD_PAGE_SIZE)); + 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)); 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); @@ -277,7 +277,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); this->list->addView(dump_card_uid); - brls::ListItem *dump_header = new brls::ListItem("gamecard_tab/list/dump_header/label"_i18n, fmt::format("gamecard_tab/list/dump_header/description"_i18n, 0)); + brls::ListItem *dump_header = new brls::ListItem("gamecard_tab/list/dump_header/label"_i18n, brls::i18n::getStr("gamecard_tab/list/dump_header/description", 0)); 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); diff --git a/source/options_tab.cpp b/source/options_tab.cpp index 5d48e24..3954a45 100644 --- a/source/options_tab.cpp +++ b/source/options_tab.cpp @@ -31,114 +31,10 @@ using namespace i18n::literals; /* For _i18n. */ namespace nxdt::views { - OptionsTabUpdateProgress::OptionsTabUpdateProgress(void) - { - this->progress_display = new brls::ProgressDisplay(); - this->progress_display->setParent(this); - - this->size_lbl = new brls::Label(brls::LabelStyle::MEDIUM, "", false); - this->size_lbl->setVerticalAlign(NVG_ALIGN_BOTTOM); - this->size_lbl->setParent(this); - - this->speed_eta_lbl = new brls::Label(brls::LabelStyle::MEDIUM, "", false); - this->speed_eta_lbl->setVerticalAlign(NVG_ALIGN_TOP); - this->speed_eta_lbl->setParent(this); - } - - OptionsTabUpdateProgress::~OptionsTabUpdateProgress(void) - { - delete this->progress_display; - delete this->size_lbl; - delete this->speed_eta_lbl; - } - - void OptionsTabUpdateProgress::SetProgress(const nxdt::tasks::DownloadTaskProgress& progress) - { - /* Update progress percentage. */ - this->progress_display->setProgress(progress.percentage, 100); - - /* Update size string. */ - this->size_lbl->setText(fmt::format("{} / {}", this->GetFormattedSizeString(static_cast(progress.current)), \ - progress.size ? this->GetFormattedSizeString(static_cast(progress.size)) : "?")); - - /* Update speed / ETA string. */ - if (progress.eta.length()) - { - this->speed_eta_lbl->setText(fmt::format("{}/s - ETA: {}", this->GetFormattedSizeString(progress.speed), progress.eta)); - } else { - this->speed_eta_lbl->setText(fmt::format("{}/s", this->GetFormattedSizeString(progress.speed))); - } - - this->invalidate(); - } - - void OptionsTabUpdateProgress::willAppear(bool resetState) - { - this->progress_display->willAppear(resetState); - } - - void OptionsTabUpdateProgress::willDisappear(bool resetState) - { - this->progress_display->willDisappear(resetState); - } - - void OptionsTabUpdateProgress::draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, brls::Style* style, brls::FrameContext* ctx) - { - /* Progress display. */ - this->progress_display->frame(ctx); - - /* Size label. */ - this->size_lbl->frame(ctx); - - /* Speed / ETA label. */ - this->speed_eta_lbl->frame(ctx); - } - - void OptionsTabUpdateProgress::layout(NVGcontext* vg, brls::Style* style, brls::FontStash* stash) - { - unsigned elem_width = roundf(static_cast(this->width) * 0.90f); - - /* Progress display. */ - this->progress_display->setBoundaries( - this->x + (this->width - elem_width) / 2, - this->y + (this->height - style->CrashFrame.buttonHeight) / 2, - elem_width, - style->CrashFrame.buttonHeight); - - this->progress_display->invalidate(true); - - /* Size label. */ - this->size_lbl->setWidth(elem_width); - this->size_lbl->invalidate(true); - - this->size_lbl->setBoundaries( - this->x + (this->width - this->size_lbl->getWidth()) / 2, - this->progress_display->getY() - this->progress_display->getHeight() / 8, - this->size_lbl->getWidth(), - this->size_lbl->getHeight()); - - /* Speed / ETA label. */ - this->speed_eta_lbl->setWidth(elem_width); - this->speed_eta_lbl->invalidate(true); - - this->speed_eta_lbl->setBoundaries( - this->x + (this->width - this->speed_eta_lbl->getWidth()) / 2, - this->progress_display->getY() + this->progress_display->getHeight() + this->progress_display->getHeight() / 8, - this->speed_eta_lbl->getWidth(), - this->speed_eta_lbl->getHeight()); - } - - std::string OptionsTabUpdateProgress::GetFormattedSizeString(double size) - { - char strbuf[0x40] = {0}; - utilsGenerateFormattedSizeString(size, strbuf, sizeof(strbuf)); - return std::string(strbuf); - } - OptionsTabUpdateFileDialog::OptionsTabUpdateFileDialog(std::string path, std::string url, bool force_https, std::string success_str) : brls::Dialog(), success_str(success_str) { /* Set content view. */ - OptionsTabUpdateProgress *update_progress = new OptionsTabUpdateProgress(); + EtaProgressDisplay *update_progress = new EtaProgressDisplay(); this->setContentView(update_progress); /* Add cancel button. */ @@ -154,9 +50,9 @@ namespace nxdt::views this->setCancelable(false); /* Subscribe to the download task. */ - this->download_task.RegisterListener([this, update_progress](const nxdt::tasks::DownloadTaskProgress& progress) { + this->download_task.RegisterListener([this, update_progress](const EtaProgressInfo& progress) { /* Update progress. */ - update_progress->SetProgress(progress); + update_progress->setProgress(progress); /* Check if the download task has finished. */ if (this->download_task.isFinished()) @@ -194,11 +90,11 @@ namespace nxdt::views this->addStage(this->changelog_list); /* Add third stage. */ - this->update_progress = new OptionsTabUpdateProgress(); + this->update_progress = new EtaProgressDisplay(); this->addStage(this->update_progress); /* Subscribe to the JSON task. */ - this->json_task.RegisterListener([this](const nxdt::tasks::DownloadTaskProgress& progress) { + this->json_task.RegisterListener([this](const EtaProgressInfo& progress) { /* Return immediately if the JSON task hasn't finished. */ if (!this->json_task.isFinished()) return; @@ -293,7 +189,7 @@ namespace nxdt::views std::stringstream ss(std::string(this->json_data.changelog)); /* Display version string at the top. */ - FocusableLabel *version_lbl = new FocusableLabel(true, false, brls::LabelStyle::CRASH, std::string(this->json_data.version), true); + FocusableLabel *version_lbl = new FocusableLabel(false, false, brls::LabelStyle::CRASH, std::string(this->json_data.version), true); version_lbl->setHorizontalAlign(NVG_ALIGN_CENTER); this->changelog_list->addView(version_lbl); @@ -356,9 +252,9 @@ namespace nxdt::views this->updateActionHint(brls::Key::B, "options_tab/update_dialog/cancel"_i18n); /* Subscribe to the NRO task. */ - this->nro_task.RegisterListener([this](const nxdt::tasks::DownloadTaskProgress& progress) { + this->nro_task.RegisterListener([this](const EtaProgressInfo& progress) { /* Update progress. */ - this->update_progress->SetProgress(progress); + this->update_progress->setProgress(progress); /* Check if the download task has finished. */ if (this->nro_task.isFinished())