From 20f6ae6bc229e87b3f3a6f864243c6d84a42edc7 Mon Sep 17 00:00:00 2001 From: jw098 Date: Wed, 24 Jun 2026 17:05:28 -0700 Subject: [PATCH 01/10] Resource Download - Settings --- .../CommonFramework/GlobalSettingsPanel.cpp | 8 +- .../CommonFramework/GlobalSettingsPanel.h | 8 +- .../GlobalResourceDownloadManager.cpp | 2 +- .../SettingsResourceDownloadOptions.cpp | 50 ++ .../SettingsResourceDownloadOptions.h | 94 +++ .../SettingsResourceDownloadRow.cpp | 488 +++++++++++++++ .../SettingsResourceDownloadRow.h | 135 +++++ .../SettingsResourceDownloadTable.cpp | 104 ++++ .../SettingsResourceDownloadTable.h | 45 ++ .../SettingsResourceDownloadWidget.cpp | 559 ++++++++++++++++++ .../SettingsResourceDownloadWidget.h | 147 +++++ SerialPrograms/cmake/SourceFiles.cmake | 16 +- 12 files changed, 1647 insertions(+), 9 deletions(-) create mode 100644 SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadOptions.cpp create mode 100644 SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadOptions.h create mode 100644 SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadRow.cpp create mode 100644 SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadRow.h create mode 100644 SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadTable.cpp create mode 100644 SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadTable.h create mode 100644 SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.cpp create mode 100644 SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.h diff --git a/SerialPrograms/Source/CommonFramework/GlobalSettingsPanel.cpp b/SerialPrograms/Source/CommonFramework/GlobalSettingsPanel.cpp index 76a3cc62b7..e3ff40a6ca 100644 --- a/SerialPrograms/Source/CommonFramework/GlobalSettingsPanel.cpp +++ b/SerialPrograms/Source/CommonFramework/GlobalSettingsPanel.cpp @@ -268,6 +268,8 @@ GlobalSettings::GlobalSettings() PA_ADD_OPTION(THEME); PA_ADD_OPTION(USE_PADDLE_OCR); PA_ADD_OPTION(USE_GPU_FOR_ML_INFERENCE); + PA_ADD_OPTION(RESOURCE_DOWNLOAD_TABLE); + PA_ADD_OPTION(DOWNLOAD_ERROR); PA_ADD_OPTION(WINDOW_SIZE); PA_ADD_OPTION(LOG_WINDOW_SIZE); PA_ADD_OPTION(LOG_WINDOW_STARTUP); @@ -451,9 +453,9 @@ void GlobalSettings::on_press(){ QDesktopServices::openUrl(QUrl::fromLocalFile(QString::fromStdString(RUNTIME_BASE_PATH()))); } - - - +void GlobalSettings::connect_row_with_download(const std::string& resource_slug, std::shared_ptr& download_ptr){ + RESOURCE_DOWNLOAD_TABLE.connect_row_with_download(resource_slug, download_ptr); +} GlobalSettings_Descriptor::GlobalSettings_Descriptor() diff --git a/SerialPrograms/Source/CommonFramework/GlobalSettingsPanel.h b/SerialPrograms/Source/CommonFramework/GlobalSettingsPanel.h index df5a1f4bbe..774e25fd99 100644 --- a/SerialPrograms/Source/CommonFramework/GlobalSettingsPanel.h +++ b/SerialPrograms/Source/CommonFramework/GlobalSettingsPanel.h @@ -17,6 +17,8 @@ #include "Common/Cpp/Options/ButtonOption.h" #include "CommonFramework/Panels/SettingsPanel.h" #include "CommonFramework/Panels/PanelTools.h" +#include "CommonFramework/ResourceDownload/SettingsResourceDownloadOptions.h" +#include "CommonFramework/ResourceDownload/SettingsResourceDownloadTable.h" //#include //using std::cout; @@ -37,7 +39,7 @@ class PerformanceOptions; class AudioPipelineOptions; class VideoPipelineOptions; class ErrorReportOption; - +class ResourceDownload; @@ -111,6 +113,8 @@ class GlobalSettings : public BatchOption, private ConfigOption::Listener, priva virtual void load_json(const JsonValue& json) override; virtual JsonValue to_json() const override; + void connect_row_with_download(const std::string& resource_slug, std::shared_ptr& download_ptr); + private: virtual void on_config_value_changed(void* object) override; virtual void on_press() override; @@ -125,6 +129,8 @@ class GlobalSettings : public BatchOption, private ConfigOption::Listener, priva Pimpl THEME; BooleanCheckBoxOption USE_PADDLE_OCR; BooleanCheckBoxOption USE_GPU_FOR_ML_INFERENCE; + SettingsResourceDownloadTable RESOURCE_DOWNLOAD_TABLE; + SettingsDownloadError DOWNLOAD_ERROR; Pimpl WINDOW_SIZE; Pimpl LOG_WINDOW_SIZE; BooleanCheckBoxOption LOG_WINDOW_STARTUP; diff --git a/SerialPrograms/Source/CommonFramework/ResourceDownload/GlobalResourceDownloadManager.cpp b/SerialPrograms/Source/CommonFramework/ResourceDownload/GlobalResourceDownloadManager.cpp index bd804194a6..c5a269d5e1 100644 --- a/SerialPrograms/Source/CommonFramework/ResourceDownload/GlobalResourceDownloadManager.cpp +++ b/SerialPrograms/Source/CommonFramework/ResourceDownload/GlobalResourceDownloadManager.cpp @@ -36,7 +36,7 @@ std::shared_ptr GlobalResourceDownloadManager::add_to_download auto download_ptr = m_download_queue.emplace_back(std::make_shared(*this, std::move(resource_metadata), m_queue_lock, m_cv)); download_ptr->add_listener(*this); - // GlobalSettings::instance().connect_row_with_download(resource_slug, download_ptr); TODO: re-enable this + GlobalSettings::instance().connect_row_with_download(resource_slug, download_ptr); download_ptr->start_download(); return download_ptr; diff --git a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadOptions.cpp b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadOptions.cpp new file mode 100644 index 0000000000..1dce848211 --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadOptions.cpp @@ -0,0 +1,50 @@ +/* Resource Download Row + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#include "SettingsResourceDownloadRow.h" +#include "SettingsResourceDownloadOptions.h" + +// #include + +#include +using std::cout; +using std::endl; + +namespace PokemonAutomation{ + +// SettingsResourceDownloadButton::~SettingsResourceDownloadButton(){} +SettingsResourceDownloadButton::SettingsResourceDownloadButton(SettingsResourceDownloadRow& p_row) + : ConfigOptionImpl(LockMode::UNLOCK_WHILE_RUNNING) + , row(p_row) + , m_enabled(true) +{} + + +SettingsResourceDeleteButton::SettingsResourceDeleteButton(SettingsResourceDownloadRow& p_row) + : ConfigOptionImpl(LockMode::UNLOCK_WHILE_RUNNING) + , row(p_row) + , m_enabled(true) +{} + + +SettingsResourceCancelButton::SettingsResourceCancelButton(SettingsResourceDownloadRow& p_row) + : ConfigOptionImpl(LockMode::UNLOCK_WHILE_RUNNING) + , row(p_row) + , m_enabled(true) +{} + + +SettingsResourceProgressBar::SettingsResourceProgressBar(SettingsResourceDownloadRow& p_row) + : ConfigOptionImpl(LockMode::UNLOCK_WHILE_RUNNING) + , row(p_row) +{} + + +SettingsDownloadError::SettingsDownloadError() + : ConfigOptionImpl(LockMode::LOCK_WHILE_RUNNING) +{} + +} diff --git a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadOptions.h b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadOptions.h new file mode 100644 index 0000000000..69e76f7e49 --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadOptions.h @@ -0,0 +1,94 @@ +/* Resource Download Row + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#ifndef PokemonAutomation_ResourceDownloadOptions_H +#define PokemonAutomation_ResourceDownloadOptions_H + +// #include "Common/Cpp/Containers/Pimpl.h" +// #include "Common/Cpp/Concurrency/AsyncTask.h" +// #include "Common/Cpp/Options/StaticTableOption.h" +// #include "ResourceDownloadHelpers.h" + + +namespace PokemonAutomation{ + +class SettingsResourceDownloadRow; + + +class SettingsResourceDownloadButton : public ConfigOptionImpl{ +public: + // ~SettingsResourceDownloadButton(); + SettingsResourceDownloadButton(SettingsResourceDownloadRow& p_row); + +public: + inline bool get_enabled(){ return m_enabled; } + inline void set_enabled(bool enabled){ + m_enabled = enabled; + } + +public: + SettingsResourceDownloadRow& row; + +private: + bool m_enabled; // button should be blocked during an active task. m_enabled is false when blocked + + + + +}; + +class SettingsResourceDeleteButton : public ConfigOptionImpl{ +public: + SettingsResourceDeleteButton(SettingsResourceDownloadRow& p_row); + +public: + inline bool get_enabled(){ return m_enabled; } + inline void set_enabled(bool enabled){ + m_enabled = enabled; + } + +public: + SettingsResourceDownloadRow& row; + +private: + bool m_enabled; +}; + +class SettingsResourceCancelButton : public ConfigOptionImpl{ +public: + SettingsResourceCancelButton(SettingsResourceDownloadRow& p_row); + +public: + inline bool get_enabled(){ return m_enabled; } + inline void set_enabled(bool enabled){ + m_enabled = enabled; + } + +public: + SettingsResourceDownloadRow& row; + +private: + bool m_enabled; +}; + +class SettingsResourceProgressBar : public ConfigOptionImpl{ +public: + SettingsResourceProgressBar(SettingsResourceDownloadRow& p_row); + + SettingsResourceDownloadRow& row; +}; + + +class SettingsDownloadError : public ConfigOptionImpl{ +public: + SettingsDownloadError(); + + +}; + + +} +#endif diff --git a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadRow.cpp b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadRow.cpp new file mode 100644 index 0000000000..cd96852384 --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadRow.cpp @@ -0,0 +1,488 @@ +/* Resource Download Row + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#include "CommonFramework/Globals.h" +#include "Common/Cpp/Containers/Pimpl.tpp" +#include "Common/Cpp/PrettyPrint.h" +#include "Common/Cpp/ListenerSet.h" +// #include "Common/Cpp/Exceptions.h" +#include "CommonFramework/Tools/GlobalThreadPools.h" +#include "CommonFramework/Exceptions/OperationFailedException.h" +#include "CommonFramework/Logging/Logger.h" +#include "CommonFramework/ResourceDownload/GlobalResourceDownloadManager.h" +#include "Common/Cpp/Filesystem.h" +#include "CommonFramework/Options/LabelCellOption.h" +// #include "SettingsResourceDownloadTable.h" +#include "SettingsResourceDownloadRow.h" + +// #include +// #include +#include + +#include +using std::cout; +using std::endl; + +namespace PokemonAutomation{ + + namespace fs = std::filesystem; + + + +///////////////////////////////////////////////////////////////////////////////////////////////////////// +// SettingsResourceDownloadRow +///////////////////////////////////////////////////////////////////////////////////////////////////////// + + +std::string resource_version_to_string(ResourceVersionStatus version){ + switch(version){ + case ResourceVersionStatus::CURRENT: + return "Current"; + case ResourceVersionStatus::OUTDATED: + return "Outdated"; + case ResourceVersionStatus::NOT_APPLICABLE: + return "--"; + case ResourceVersionStatus::FUTURE_VERSION: + return "Unsupported future version.
Please update the Computer Control program."; + default: + throw InternalProgramError(nullptr, PA_CURRENT_FUNCTION, "resource_version_to_string: Unknown enum."); + } +} + +std::string is_downloaded_string(bool is_downloaded){ + return is_downloaded ? "Yes" : "--"; +} + +struct SettingsResourceDownloadRow::Data{ + Data( + std::string& resource_name, + size_t file_size, + bool is_downloaded, + std::optional version_num, + ResourceVersionStatus version_status + ) + : m_resource_name(LockMode::LOCK_WHILE_RUNNING, resource_name) + , m_file_size(file_size) + , m_file_size_label(LockMode::LOCK_WHILE_RUNNING, tostr_bytes(file_size)) + , m_is_downloaded(is_downloaded) + , m_is_downloaded_label(LockMode::LOCK_WHILE_RUNNING, is_downloaded_string(is_downloaded)) + , m_version_num(version_num) + , m_version_status(version_status) + , m_version_status_label(LockMode::LOCK_WHILE_RUNNING, resource_version_to_string(version_status)) + {} + + ListenerSet listeners; + + LabelCellOption m_resource_name; + + size_t m_file_size; + LabelCellOption m_file_size_label; + + bool m_is_downloaded; + LabelCellOption m_is_downloaded_label; + + std::optional m_version_num; + ResourceVersionStatus m_version_status; + LabelCellOption m_version_status_label; + + +}; + +void SettingsResourceDownloadRow::set_version_status(ResourceVersionStatus version_status){ + m_data->m_version_status = version_status; + m_data->m_version_status_label.set_text(resource_version_to_string(version_status)); +} + + +void SettingsResourceDownloadRow::set_is_downloaded(bool is_downloaded){ + m_data->m_is_downloaded = is_downloaded; + m_data->m_is_downloaded_label.set_text(is_downloaded_string(is_downloaded)); +} + +void SettingsResourceDownloadRow::update_table_label(bool success){ + set_is_downloaded(success); + set_version_status(success ? ResourceVersionStatus::CURRENT : ResourceVersionStatus::NOT_APPLICABLE); +} + + + +SettingsResourceDownloadRow::~SettingsResourceDownloadRow(){ + // cout << "~SettingsResourceDownloadRow" << endl; + if (m_download_ptr) { + m_download_ptr->remove_listener(*this); + } + m_pre_download_thread.wait_and_ignore_exceptions(); + m_delete_thread.wait_and_ignore_exceptions(); +} +SettingsResourceDownloadRow::SettingsResourceDownloadRow( + std::string resource_slug, + DownloadedResourceMetadata local_metadata, + bool is_downloaded, + std::optional version_num, + ResourceVersionStatus version_status +) + : StaticTableRow(local_metadata.resource_name) + , m_action_state(ActionState::READY) + , m_resource_slug(resource_slug) + , m_local_metadata(local_metadata) + , m_data(CONSTRUCT_TOKEN, local_metadata.resource_name, local_metadata.size_decompressed_bytes, is_downloaded, version_num, version_status) + , m_download_button(*this) + , m_delete_button(*this) + , m_cancel_button(*this) + , m_progress_bar(*this) +{ + PA_ADD_STATIC(m_data->m_resource_name); + PA_ADD_STATIC(m_data->m_file_size_label); + PA_ADD_STATIC(m_data->m_is_downloaded_label); + PA_ADD_STATIC(m_data->m_version_status_label); + + PA_ADD_STATIC(m_download_button); + PA_ADD_STATIC(m_delete_button); + PA_ADD_STATIC(m_cancel_button); + PA_ADD_STATIC(m_progress_bar); +} + + + +const DownloadedResourceMetadata& SettingsResourceDownloadRow::fetch_remote_metadata(){ + + if (m_cached_metadata.has_value()){ + return m_cached_metadata.value(); + } + + Logger& logger = global_logger_tagged(); + std::vector all_remote_metadata; + + try{ + all_remote_metadata = remote_resource_download_list(); + }catch(OperationFailedException&){ + std::cerr << "SettingsResourceDownloadRow::fetch_remote_metadata: Error" << endl; + throw_and_log(logger, ErrorReport::NO_ERROR_REPORT, + "Error: Download failed. Failed to fetch the list of available downloads. Check your internet connection."); + } + + std::string resource_name = m_data->m_resource_name.text(); + + for (const DownloadedResourceMetadata& remote_metadata : all_remote_metadata){ + if (remote_metadata.resource_name == resource_name){ + m_cached_metadata = remote_metadata; + return m_cached_metadata.value(); + } + } + + // if corresponding remote_metadata not found + throw_and_log(logger, ErrorReport::NO_ERROR_REPORT, + "fetch_remote_metadata: Resource no longer available for download. We recommend updating the Computer Control program."); + +} + + + +void SettingsResourceDownloadRow::ensure_remote_metadata_loaded(){ + m_pre_download_thread = GlobalThreadPools::unlimited_normal().dispatch_now_blocking( + [this]{ + try { + if (!is_given_action_state(ActionState::PRE_DOWNLOAD)){ + return; + } + + // std::this_thread::sleep_for(std::chrono::seconds(1)); + std::string predownload_warning; + try { + const DownloadedResourceMetadata& remote_metadata = fetch_remote_metadata(); + predownload_warning = predownload_warning_summary(remote_metadata); + }catch(OperationFailedException& e){ + predownload_warning = e.message(); + } + // cout << "Fetched remote metadata" << endl; + // throw InternalProgramError(nullptr, PA_CURRENT_FUNCTION, "testing"); + // Logger& logger = global_logger_tagged(); + // throw_and_log(logger, ErrorReport::NO_ERROR_REPORT, "test"); + + // update_action_state(ActionState::READY); + report_metadata_fetch_finished(predownload_warning); + + }catch(OperationFailedException&){ + // cout << "failed" << endl; + // update_table_label(false); + update_action_state(ActionState::READY); + GlobalResourceDownloadManager::instance().report_download_failed(m_resource_slug); + return; + }catch(...){ + // update_table_label(false); + update_action_state(ActionState::READY); + // cout << "Exception thrown in thread" << endl; + GlobalResourceDownloadManager::instance().report_unexpected_exception_caught("Error: SettingsResourceDownloadButton::ensure_remote_metadata_loaded: Unknown exception. Report this as an error."); + return; + } + + } + ); + +} + +std::string SettingsResourceDownloadRow::predownload_warning_summary(const DownloadedResourceMetadata& remote_metadata){ + + std::string predownload_warning; + + uint16_t local_version_num = m_local_metadata.version_num.value(); + + uint16_t remote_version_num = remote_metadata.version_num.value(); + size_t compressed_size = remote_metadata.size_compressed_bytes; + size_t decompressed_size = remote_metadata.size_decompressed_bytes; + + std::string disk_space_requirement = "This will require " + tostr_bytes(decompressed_size + compressed_size) + " of free space"; + + if (local_version_num < remote_version_num){ + predownload_warning = "The resource you are downloading is a more updated version than the program expects. " + "This may or may not cause issues with the programs. " + "We recommend updating the Computer Control program.
" + + disk_space_requirement; + }else if (local_version_num == remote_version_num){ + predownload_warning = "Update available.
" + disk_space_requirement; + }else if (local_version_num > remote_version_num){ + predownload_warning = "The resource you are downloading is a less updated version than the program expects. " + "Please report this as a bug.
" + + disk_space_requirement; + } + + return predownload_warning; +} + + + +void SettingsResourceDownloadRow::start_download(){ + if (!is_given_action_state(ActionState::PRE_DOWNLOAD)){ + return; + } + + update_action_state(ActionState::DOWNLOADING); + + cancel_download_thread(); // cancels old download thread + + try{ + std::shared_ptr download_ptr = GlobalResourceDownloadManager::instance().add_to_download_list(m_resource_slug); + + }catch(OperationFailedException&){ + update_action_state(ActionState::READY); + } + +} + + +void SettingsResourceDownloadRow::start_delete(){ + m_delete_thread = GlobalThreadPools::unlimited_normal().dispatch_now_blocking( + [this]{ + try { + + // throw InternalProgramError(nullptr, PA_CURRENT_FUNCTION, "test."); + // Logger& logger = global_logger_tagged(); + // throw_and_log(logger, ErrorReport::NO_ERROR_REPORT, "test"); + + if (!is_given_action_state(ActionState::PRE_DELETE)){ + return; + } + update_action_state(ActionState::DELETING); + + std::string resource_name = m_local_metadata.resource_name; + + std::string resource_directory = DOWNLOADED_RESOURCE_PATH() + resource_name; + // delete directory and the old resource + fs::remove_all(Filesystem::Path(resource_directory)); + + // update the table labels + set_is_downloaded(false); + set_version_status(ResourceVersionStatus::NOT_APPLICABLE); + + update_action_state(ActionState::READY); + }catch(OperationFailedException& e){ + std::cerr << e.message() << endl; + update_action_state(ActionState::READY); + GlobalResourceDownloadManager::instance().report_unexpected_exception_caught( + "Error: SettingsResourceDownloadButton::start_delete: Unexpected OperationFailedException exception. Report this as an error."); + return; + }catch(...){ + update_action_state(ActionState::READY); + GlobalResourceDownloadManager::instance().report_unexpected_exception_caught( + "Error: SettingsResourceDownloadButton::start_delete: Unknown exception. Report this as an error."); + return; + } + } + ); + +} + + +void SettingsResourceDownloadRow::update_action_state(ActionState state){ + std::lock_guard lock(m_action_state_lock); + { + switch (state){ + case ActionState::PRE_DOWNLOAD: + // action state can only enter the PRE_DOWNLOAD state + // if going from the READY state + if (m_action_state == ActionState::READY){ + m_download_button.set_enabled(false); + m_delete_button.set_enabled(false); + m_cancel_button.set_enabled(true); + m_action_state = state; + cout << "ActionState::PRE_DOWNLOAD" << endl; + } + break; + case ActionState::DOWNLOADING: + if (m_action_state == ActionState::PRE_DOWNLOAD || m_action_state == ActionState::PRE_CANCEL || m_action_state == ActionState::READY){ + m_download_button.set_enabled(false); + m_delete_button.set_enabled(false); + m_cancel_button.set_enabled(true); + m_action_state = state; + cout << "ActionState::DOWNLOADING" << endl; + } + break; + case ActionState::PRE_DELETE: + // action state can only enter the PRE_DELETE state + // if going from the READY state + if (m_action_state == ActionState::READY){ + m_download_button.set_enabled(false); + m_delete_button.set_enabled(false); + m_cancel_button.set_enabled(false); + m_action_state = state; + cout << "ActionState::PRE_DELETE" << endl; + } + break; + case ActionState::DELETING: + // action state can only enter the DELETING state + // if going from the PRE_DELETE state + if (m_action_state == ActionState::PRE_DELETE){ + m_download_button.set_enabled(false); + m_delete_button.set_enabled(false); + m_cancel_button.set_enabled(false); + m_action_state = state; + cout << "ActionState::DELETING" << endl; + } + break; + case ActionState::PRE_CANCEL: + // action state can only enter the PRE_CANCEL state + // if going from the DOWNLOADING state + if (m_action_state == ActionState::DOWNLOADING){ + m_download_button.set_enabled(false); + m_delete_button.set_enabled(false); + m_cancel_button.set_enabled(false); + m_action_state = state; + cout << "ActionState::PRE_CANCEL" << endl; + } + break; + case ActionState::CANCELLING: + // action state can only enter the CANCELLING state + // if going from the PRE_CANCEL state + if (m_action_state == ActionState::PRE_CANCEL){ + m_download_button.set_enabled(false); + m_delete_button.set_enabled(false); + m_cancel_button.set_enabled(false); + m_action_state = state; + cout << "ActionState::CANCELLING" << endl; + } + break; + case ActionState::READY: + m_download_button.set_enabled(true); + m_delete_button.set_enabled(true); + m_cancel_button.set_enabled(true); + m_action_state = state; + cout << "ActionState::READY" << endl; + break; + default: + throw InternalProgramError(nullptr, PA_CURRENT_FUNCTION, "update_action_state: Unknown enum."); + } + } + + report_action_state_updated(); +} + +ActionState SettingsResourceDownloadRow::get_action_state(){ + std::lock_guard lock(m_action_state_lock); + return m_action_state; +} + +bool SettingsResourceDownloadRow::is_given_action_state(ActionState state){ + std::lock_guard lock(m_action_state_lock); + return m_action_state == state; +} + +void SettingsResourceDownloadRow::cancel_download_thread(){ + if (m_download_ptr){ // if download is active + m_download_ptr->cancel_download(); + } +} + + +void SettingsResourceDownloadRow::connect_with_download(std::shared_ptr download_ptr){ + if (m_download_ptr){ + m_download_ptr->remove_listener(*this); + } + m_download_ptr = std::move(download_ptr); + m_download_ptr->add_listener(*this); + update_action_state(ActionState::DOWNLOADING); +} + + +///////////////////////// +// Listener +///////////////////////// +void SettingsResourceDownloadRow::add_listener(Listener& listener){ + auto scope = m_lifetime_sanitizer.check_scope(); + m_data->listeners.add(listener); +} +void SettingsResourceDownloadRow::remove_listener(Listener& listener){ + auto scope = m_lifetime_sanitizer.check_scope(); + m_data->listeners.remove(listener); +} + +void SettingsResourceDownloadRow::report_download_progress(uint64_t bytes_done, uint64_t total_bytes){ + auto scope = m_lifetime_sanitizer.check_scope(); + m_data->listeners.run_method(&Listener::on_download_progress, bytes_done, total_bytes); +} +void SettingsResourceDownloadRow::report_unzip_progress(uint64_t bytes_done, uint64_t total_bytes){ + auto scope = m_lifetime_sanitizer.check_scope(); + m_data->listeners.run_method(&Listener::on_unzip_progress, bytes_done, total_bytes); +} +void SettingsResourceDownloadRow::report_hash_progress(uint64_t bytes_done, uint64_t total_bytes){ + auto scope = m_lifetime_sanitizer.check_scope(); + m_data->listeners.run_method(&Listener::on_hash_progress, bytes_done, total_bytes); +} + +void SettingsResourceDownloadRow::report_metadata_fetch_finished(const std::string& popup_message){ + auto scope = m_lifetime_sanitizer.check_scope(); + m_data->listeners.run_method(&Listener::on_metadata_fetch_finished, popup_message); +} + +void SettingsResourceDownloadRow::report_action_state_updated(){ + auto scope = m_lifetime_sanitizer.check_scope(); + m_data->listeners.run_method(&Listener::on_action_state_updated); +} + + +//////////////////////////////// +// ResourceDownload::Listener +//////////////////////////////// +void SettingsResourceDownloadRow::on_download_progress(uint64_t bytes_done, uint64_t total_bytes){ + report_download_progress(bytes_done, total_bytes); +} +void SettingsResourceDownloadRow::on_unzip_progress(uint64_t bytes_done, uint64_t total_bytes){ + report_unzip_progress(bytes_done, total_bytes); +} +void SettingsResourceDownloadRow::on_hash_progress(uint64_t bytes_done, uint64_t total_bytes){ + report_hash_progress(bytes_done, total_bytes); +} + +void SettingsResourceDownloadRow::on_download_finished(bool success, const std::string& resource_slug){ + // we can't run `download_ptr->remove_listener(*this)` in this function + // since it results in deadlock, since this function is part of the listener loop + m_download_ptr.reset(); + + update_action_state(ActionState::READY); + update_table_label(success); +} + + +} diff --git a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadRow.h b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadRow.h new file mode 100644 index 0000000000..459da9e2f1 --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadRow.h @@ -0,0 +1,135 @@ +/* Resource Download Row + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#ifndef PokemonAutomation_ResourceDownloadRow_H +#define PokemonAutomation_ResourceDownloadRow_H + +#include "Common/Cpp/Containers/Pimpl.h" +#include "Common/Cpp/Concurrency/AsyncTask.h" +// #include "Common/Cpp/Concurrency/ConditionVariable.h" +#include "Common/Cpp/LifetimeSanitizer.h" +// #include "CommonFramework/Tools/GlobalThreadPools.h" +#include "Common/Cpp/Options/StaticTableOption.h" +#include "ResourceDownloadHelpers.h" +#include "ResourceDownload.h" +#include "SettingsResourceDownloadOptions.h" +// #include + +namespace PokemonAutomation{ + + +enum class ActionState{ + PRE_DOWNLOAD, + DOWNLOADING, + PRE_DELETE, + DELETING, + PRE_CANCEL, + CANCELLING, + READY, +}; +class SettingsResourceDownloadRow : public StaticTableRow, public ResourceDownload::Listener{ +public: + ~SettingsResourceDownloadRow(); + SettingsResourceDownloadRow( + std::string resource_slug, + DownloadedResourceMetadata local_metadata, + bool is_downloaded, + std::optional version_num, + ResourceVersionStatus version_status + ); + +public: + struct Listener{ + virtual void on_download_progress(uint64_t bytes_done, uint64_t total_bytes){} + virtual void on_unzip_progress(uint64_t bytes_done, uint64_t total_bytes){} + virtual void on_hash_progress(uint64_t bytes_done, uint64_t total_bytes){} + + virtual void on_metadata_fetch_finished(const std::string& popup_message){} + + virtual void on_action_state_updated(){} + }; + + void add_listener(Listener& listener); + void remove_listener(Listener& listener); + + void report_download_progress(uint64_t bytes_done, uint64_t total_bytes); + void report_unzip_progress(uint64_t bytes_done, uint64_t total_bytes); + void report_hash_progress(uint64_t bytes_done, uint64_t total_bytes); + + void report_metadata_fetch_finished(const std::string& popup_message); + + void report_action_state_updated(); + +public: // ResourceDownload::Listener + virtual void on_download_progress(uint64_t bytes_done, uint64_t total_bytes) override; + virtual void on_unzip_progress(uint64_t bytes_done, uint64_t total_bytes) override; + virtual void on_hash_progress(uint64_t bytes_done, uint64_t total_bytes) override; + + // NOTE: this runs regardless of success or failure + virtual void on_download_finished(bool success, const std::string& resource_slug) override; + +public: + std::string get_resource_slug(){ return m_resource_slug; } + void set_version_status(ResourceVersionStatus version_status); + void set_is_downloaded(bool is_downloaded); + void update_table_label(bool success); + + void ensure_remote_metadata_loaded(); + std::string predownload_warning_summary(const DownloadedResourceMetadata& remote_metadata); + // get the DownloadedResourceMetadata from the remote JSON, that corresponds to this button/row + const DownloadedResourceMetadata& fetch_remote_metadata(); + // DownloadedResourceMetadata initialize_local_metadata(); + + void start_download(); + + void start_delete(); + + // READY: can come from any state + // PRE_DOWNLOAD, PRE_DELETE, PRE_CANCEL: can only come from READY + // DELETING, CANCELLING: can only come from their respective PRE state + // DOWNLOADING: can come from either PRE_DOWNLOAD or PRE_CANCEL + void update_action_state(ActionState state); + + ActionState get_action_state(); + + bool is_given_action_state(ActionState state); + + void cancel_download_thread(); + + // - updates m_download_ptr to point to the given download_ptr + // - adds this object as a listener to download_ptr + void connect_with_download(std::shared_ptr download_ptr); + +private: + ActionState m_action_state; + std::string m_resource_slug; + DownloadedResourceMetadata m_local_metadata; + struct Data; + Pimpl m_data; + + SettingsResourceDownloadButton m_download_button; + SettingsResourceDeleteButton m_delete_button; + SettingsResourceCancelButton m_cancel_button; + SettingsResourceProgressBar m_progress_bar; + + AsyncTask m_pre_download_thread; + AsyncTask m_delete_thread; + + std::optional m_cached_metadata; + + std::shared_ptr m_download_ptr; + + Mutex m_action_state_lock; + + LifetimeSanitizer m_lifetime_sanitizer; + + + + +}; + +} +#endif diff --git a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadTable.cpp b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadTable.cpp new file mode 100644 index 0000000000..84d9505cd9 --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadTable.cpp @@ -0,0 +1,104 @@ +/* Resource Download Table + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#include "CommonFramework/Globals.h" +#include "Common/Cpp/Exceptions.h" +// #include "CommonFramework/Logging/Logger.h" +// #include "CommonFramework/Tools/GlobalThreadPools.h" +// #include "CommonFramework/Tools/FileDownloader.h" +// #include "CommonFramework/Exceptions/OperationFailedException.h" +// #include "Common/Cpp/Json/JsonArray.h" +// #include "Common/Cpp/Json/JsonObject.h" +#include "Common/Cpp/Filesystem.h" +#include "ResourceDownload.h" +#include "SettingsResourceDownloadRow.h" +#include "SettingsResourceDownloadTable.h" + +// #include +// #include +// #include + +#include +using std::cout; +using std::endl; + +namespace PokemonAutomation{ + + +std::vector> SettingsResourceDownloadTable::get_resource_download_rows(){ + std::vector> resource_rows; + std::vector resource_list; + try{ + resource_list = expected_resource_download_list(); + }catch(FileException&){ + return {}; + } + + for (uint16_t index = 0; index < resource_list.size(); index++){ + DownloadedResourceMetadata resource = resource_list[index]; + std::string resource_name = resource.resource_name; + + auto [is_downloaded, version_status, current_version_num] = get_local_version_info(resource_name); + + resource_rows.emplace_back(std::make_unique(resource_name, resource, is_downloaded, current_version_num, version_status)); + } + + return resource_rows; +} + + + + +SettingsResourceDownloadTable::~SettingsResourceDownloadTable(){ + // m_worker.wait_and_ignore_exceptions(); +} + +SettingsResourceDownloadTable::SettingsResourceDownloadTable() + : StaticTableOption("Resource Downloading:
Download resources not included in the initial download of the program.", LockMode::LOCK_WHILE_RUNNING, false) + , m_resource_rows(get_resource_download_rows()) +{ + add_resource_download_rows(); + + finish_construction(); +} +std::vector SettingsResourceDownloadTable::make_header() const{ + std::vector ret{ + "Resource", + "Size", + "Downloaded", + "Version", + "", + "", + "", + "", + }; + return ret; +} + + +void SettingsResourceDownloadTable::add_resource_download_rows(){ + for (std::unique_ptr& row_ptr : m_resource_rows){ + add_row(row_ptr.get()); + } +} + +void SettingsResourceDownloadTable::connect_row_with_download(const std::string& resource_slug, std::shared_ptr& download_ptr){ + + for (const auto& row_ptr : m_resource_rows) { + if (row_ptr->get_resource_slug() == resource_slug) { + // download_ptr->add_listener(*row_ptr); + row_ptr->connect_with_download(download_ptr); + return; + } + } + + // resource_slug not found within m_resource_rows + throw InternalProgramError(nullptr, PA_CURRENT_FUNCTION, "connect_row_with_download: resource_slug not found within m_resource_rows."); +} + + + +} diff --git a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadTable.h b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadTable.h new file mode 100644 index 0000000000..307deca070 --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadTable.h @@ -0,0 +1,45 @@ +/* Resource Download Table + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#ifndef PokemonAutomation_ResourceDownloadTable_H +#define PokemonAutomation_ResourceDownloadTable_H + +#include +#include "Common/Cpp/Concurrency/AsyncTask.h" +#include "Common/Cpp/Concurrency/Mutex.h" +#include "Common/Cpp/Concurrency/ConditionVariable.h" +#include "Common/Cpp/Options/StaticTableOption.h" +// #include "SettingsResourceDownloadRow.h" + +namespace PokemonAutomation{ + +class SettingsResourceDownloadRow; +class ResourceDownload; + +class SettingsResourceDownloadTable : public StaticTableOption{ +public: + ~SettingsResourceDownloadTable(); + SettingsResourceDownloadTable(); + + virtual std::vector make_header() const override; + + void connect_row_with_download(const std::string& resource_slug, std::shared_ptr& download_ptr); + +private: + std::vector> get_resource_download_rows(); + void add_resource_download_rows(); + + +private: + // we need to keep a handle on each Row, so that we can edit m_is_downloaded_label later on. + std::vector> m_resource_rows; + +}; + + + +} +#endif diff --git a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.cpp b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.cpp new file mode 100644 index 0000000000..5c4d05fed5 --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.cpp @@ -0,0 +1,559 @@ +/* Resource Download Widget + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#include +#include +#include +#include +#include +#include +#include "CommonFramework/Logging/Logger.h" +#include "Common/Cpp/Exceptions.h" + +#include "CommonFramework/Notifications/ProgramNotifications.h" +#include "SettingsResourceDownloadWidget.h" + +#include +using std::cout; +using std::endl; + +namespace PokemonAutomation{ + + +///////////////////////////////////////////////////////////////////////////////////////////////////////// +// SettingsDownloadButtonWidget +///////////////////////////////////////////////////////////////////////////////////////////////////////// + +template class RegisterConfigWidget; +SettingsDownloadButtonWidget::~SettingsDownloadButtonWidget(){ + // cout << "Destructor for SettingsDownloadButtonWidget" << endl; + // m_value.disconnect(this); + m_row.remove_listener(*this); +} +SettingsDownloadButtonWidget::SettingsDownloadButtonWidget(QWidget& parent, SettingsResourceDownloadButton& value) + : QWidget(&parent) + , ConfigWidget(value, *this) + , m_value(value) + , m_row(value.row) +{ + + QHBoxLayout* layout = new QHBoxLayout(this); + layout->setContentsMargins(0, 0, 0, 0); + + m_button = new QPushButton("Download", this); + // m_widget = this; + + layout->addWidget(m_button); + + // cout << "Constructor for SettingsDownloadButtonWidget" << endl; + + QFont font; + font.setBold(true); + m_button->setFont(font); + m_button->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + + QFontMetrics metrics(m_button->font()); + int minWidth = metrics.horizontalAdvance("Downloading..."); + m_button->setMinimumWidth(minWidth); + + // Button should be disabled when in the middle of downloading + // this status is stored within SettingsResourceDownloadButton::m_enabled + // when the button is clicked, m_enabled is set to false + // when te download is done, m_enabled is set back to true + // the UI is updated to reflect the status of m_enabled, by using update_UI_state + + + // update the UI based on m_enabled, when the button is constructed + update_UI_state(); + + // when the button is clicked, runs row.update_action_state(), which updates the button state + // also, fetch json + connect( + m_button, &QPushButton::clicked, + this, [this](){ + if (!m_row.is_given_action_state(ActionState::READY)){ + return; + } + m_row.update_action_state(ActionState::PRE_DOWNLOAD); + m_row.ensure_remote_metadata_loaded(); + } + ); + + + m_row.add_listener(*this); +} + + +void SettingsDownloadButtonWidget::update_UI_state(){ + if (m_value.get_enabled()){ + m_button->setEnabled(true); + m_button->setText("Download"); + }else{ + m_button->setEnabled(false); + if (m_row.is_given_action_state(ActionState::PRE_DOWNLOAD) + || m_row.is_given_action_state(ActionState::DOWNLOADING)) + { + m_button->setText("Downloading..."); + } + } +} + + +void SettingsDownloadButtonWidget::show_download_confirm_box( + const std::string& title, + const std::string& message_body +){ + QMessageBox box; + QPushButton* ok = box.addButton(QMessageBox::Ok); + QPushButton* cancel = box.addButton("Cancel", QMessageBox::NoRole); + box.setEscapeButton(cancel); +// cout << "ok = " << ok << endl; +// cout << "skip = " << skip << endl; + + box.setTextFormat(Qt::RichText); + std::string text = message_body; + // text += make_text_url(link_url, link_text); + // text += get_changes(node); + + + box.setWindowTitle(QString::fromStdString(title)); + box.setText(QString::fromStdString(text)); + +// box.open(); + + box.exec(); + + QAbstractButton* clicked = box.clickedButton(); +// cout << "clicked = " << clicked << endl; + if (clicked == ok){ + cout << "Clicked Ok to Download" << endl; + + m_row.start_download(); + return; + } + if (clicked == cancel){ + m_row.update_action_state(ActionState::READY); + return; + } +} + +// when json has been fetched, open the update box. +// When click Ok in update box, start the download. If click cancel, re-enable the download button +void SettingsDownloadButtonWidget::on_metadata_fetch_finished(const std::string& popup_message){ + QMetaObject::invokeMethod(this, [this, popup_message]{ + show_download_confirm_box("Download", popup_message); + }, Qt::QueuedConnection); + +} + + +void SettingsDownloadButtonWidget::on_action_state_updated(){ + QMetaObject::invokeMethod(this, [this]{ + update_UI_state(); + }, Qt::QueuedConnection); +} + + +///////////////////////////////////////////////////////////////////////////////////////////////////////// +// SettingsDeleteButtonWidget +///////////////////////////////////////////////////////////////////////////////////////////////////////// + +template class RegisterConfigWidget; +SettingsDeleteButtonWidget::~SettingsDeleteButtonWidget(){ + m_row.remove_listener(*this); +} +SettingsDeleteButtonWidget::SettingsDeleteButtonWidget(QWidget& parent, SettingsResourceDeleteButton& value) + : QWidget(&parent) + , ConfigWidget(value, *this) + , m_value(value) + , m_row(value.row) +{ + QHBoxLayout* layout = new QHBoxLayout(this); + layout->setContentsMargins(0, 0, 0, 0); + + m_button = new QPushButton("Delete", this); + // m_widget = m_button; + + layout->addWidget(m_button); + + QFont font; + font.setBold(true); + m_button->setFont(font); + m_button->setText("Delete"); + m_button->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + + QFontMetrics metrics(m_button->font()); + int minWidth = metrics.horizontalAdvance("Deleting..."); + m_button->setMinimumWidth(minWidth); + + + // update the UI based on m_enabled, when the button is constructed + update_UI_state(); + + // when the button is clicked, runs row.update_action_state(), which updates the button state + // also, show the delete confirm box + connect( + m_button, &QPushButton::clicked, + this, [&](bool){ + if (!m_row.is_given_action_state(ActionState::READY)){ + return; + } + m_row.update_action_state(ActionState::PRE_DELETE); + show_delete_confirm_box(); + // cout << "Clicked Delete Button" << endl; + } + ); + + m_row.add_listener(*this); +} + + +void SettingsDeleteButtonWidget::update_UI_state(){ + if (m_value.get_enabled()){ + m_button->setEnabled(true); + m_button->setText("Delete"); + }else{ + m_button->setEnabled(false); + if (m_row.is_given_action_state(ActionState::PRE_DELETE) + || m_row.is_given_action_state(ActionState::DELETING) + ){ + m_button->setText("Deleting..."); + } + } +} + + +void SettingsDeleteButtonWidget::show_delete_confirm_box(){ + QMessageBox box; + QPushButton* yes = box.addButton(QMessageBox::Yes); + QPushButton* cancel = box.addButton("Cancel", QMessageBox::NoRole); + box.setEscapeButton(cancel); +// cout << "ok = " << ok << endl; +// cout << "skip = " << skip << endl; + + box.setTextFormat(Qt::RichText); + std::string title = "Delete"; + std::string message_body = "Are you sure you want to delete this resource?"; + + box.setWindowTitle(QString::fromStdString(title)); + box.setText(QString::fromStdString(message_body)); + +// box.open(); + + box.exec(); + + QAbstractButton* clicked = box.clickedButton(); +// cout << "clicked = " << clicked << endl; + if (clicked == yes){ + cout << "Clicked Yes to Delete" << endl; + + m_row.start_delete(); + return; + } + if (clicked == cancel){ + m_row.update_action_state(ActionState::READY); + return; + } +} + +// when action_state_updated, update the UI state to match +void SettingsDeleteButtonWidget::on_action_state_updated(){ + QMetaObject::invokeMethod(this, [this]{ + update_UI_state(); + }, Qt::QueuedConnection); + +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////// +// SettingsCancelButtonWidget +///////////////////////////////////////////////////////////////////////////////////////////////////////// + +template class RegisterConfigWidget; +SettingsCancelButtonWidget::~SettingsCancelButtonWidget(){ + m_row.remove_listener(*this); +} +SettingsCancelButtonWidget::SettingsCancelButtonWidget(QWidget& parent, SettingsResourceCancelButton& value) + : QWidget(&parent) + , ConfigWidget(value, *this) + , m_value(value) + , m_row(value.row) +{ + QHBoxLayout* layout = new QHBoxLayout(this); + layout->setContentsMargins(0, 0, 0, 0); + + m_button = new QPushButton("Cancel", this); + // m_widget = m_button; + + layout->addWidget(m_button); + + QFont font; + font.setBold(true); + m_button->setFont(font); + m_button->setText("Cancel"); + m_button->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + + QFontMetrics metrics(m_button->font()); + int minWidth = metrics.horizontalAdvance("Cancelling..."); + m_button->setMinimumWidth(minWidth); + + // update the UI based on m_enabled, when the button is constructed + update_UI_state(); + + // when the button is clicked, runs row.update_action_state(), which updates the button state + // also, set cancel state to true + connect( + m_button, &QPushButton::clicked, + this, [&](bool){ + if (!m_row.is_given_action_state(ActionState::DOWNLOADING)){ + return; + } + m_row.update_action_state(ActionState::PRE_CANCEL); + show_cancel_confirm_box(); + cout << "Clicked Cancel Button" << endl; + } + ); + + m_row.add_listener(*this); + +} + +void SettingsCancelButtonWidget::show_cancel_confirm_box(){ + QMessageBox box; + QPushButton* yes = box.addButton(QMessageBox::Yes); + QPushButton* cancel = box.addButton("Cancel", QMessageBox::NoRole); + box.setEscapeButton(cancel); +// cout << "ok = " << ok << endl; +// cout << "skip = " << skip << endl; + + box.setTextFormat(Qt::RichText); + std::string title = "Cancel Download"; + std::string message_body = "Are you sure you want to cancel this download?"; + + box.setWindowTitle(QString::fromStdString(title)); + box.setText(QString::fromStdString(message_body)); + +// box.open(); + + box.exec(); + + QAbstractButton* clicked = box.clickedButton(); +// cout << "clicked = " << clicked << endl; + if (clicked == yes){ + cout << "Clicked Yes to Cancel" << endl; + + if (!m_row.is_given_action_state(ActionState::PRE_CANCEL)){ + // if the download finishes and goes back to READY state before the user clicks Yes to cancel + // then nothing happens + return; + } + + m_row.update_action_state(ActionState::CANCELLING); + + m_row.cancel_download_thread(); + + return; + } + if (clicked == cancel){ + if (!m_row.is_given_action_state(ActionState::PRE_CANCEL)){ + return; + } + + m_row.update_action_state(ActionState::DOWNLOADING); + return; + } +} + + +void SettingsCancelButtonWidget::update_UI_state(){ + if (m_value.get_enabled()){ + m_button->setEnabled(true); + m_button->setText("Cancel"); + }else{ + m_button->setEnabled(false); + if (m_row.is_given_action_state(ActionState::PRE_CANCEL) + || m_row.is_given_action_state(ActionState::CANCELLING) + ){ + m_button->setText("Cancelling..."); + } + } +} + +// when action_state_updated, update the UI state to match +void SettingsCancelButtonWidget::on_action_state_updated(){ + QMetaObject::invokeMethod(this, [this]{ + update_UI_state(); + }, Qt::QueuedConnection); +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////// +// SettingsProgressBarWidget +///////////////////////////////////////////////////////////////////////////////////////////////////////// + +template class RegisterConfigWidget; +SettingsProgressBarWidget::~SettingsProgressBarWidget(){ + // cout << "Destructor for SettingsProgressBarWidget" << endl; + m_row.remove_listener(*this); +} +SettingsProgressBarWidget::SettingsProgressBarWidget(QWidget& parent, SettingsResourceProgressBar& value) + : QWidget(&parent) + , ConfigWidget(value, *this) + // , m_value(value) + , m_row(value.row) +{ + + // 1. Instantiate the widgets + m_status_label = new QLabel("", this); + m_progress_bar = new QProgressBar(this); + + // cout << "Constructor for SettingsProgressBarWidget" << endl; + + // 2. Configure the progress bar + m_progress_bar->setRange(0, 100); + m_progress_bar->setValue(0); + m_progress_bar->setTextVisible(true); // Shows % inside the bar + m_progress_bar->hide(); + + // 3. Create a horizontal layout to hold them + QHBoxLayout *layout = new QHBoxLayout(); + layout->addWidget(m_status_label); + layout->addWidget(m_progress_bar); + + this->setLayout(layout); + this->setMinimumWidth(170); + + m_row.add_listener(*this); +} + + +void SettingsProgressBarWidget::update_UI_state(){ + ActionState state = m_row.get_action_state(); + switch (state){ + case ActionState::PRE_DOWNLOAD: + case ActionState::DOWNLOADING: + m_status_label->setText("Downloading"); + if (m_progress_bar->isHidden()) { + m_progress_bar->show(); + } + break; + case ActionState::PRE_DELETE: + case ActionState::DELETING: + // m_status_label->setText(""); + // m_progress_bar->hide(); + m_progress_bar->setValue(0); + break; + case ActionState::PRE_CANCEL: + case ActionState::CANCELLING: + // m_status_label->setText(""); + // m_progress_bar->hide(); + m_progress_bar->setValue(0); + break; + case ActionState::READY: + m_status_label->setText(""); + m_progress_bar->hide(); + m_progress_bar->setValue(0); + break; + default: + throw InternalProgramError(nullptr, PA_CURRENT_FUNCTION, "update_UI_state: Unknown enum."); + } +} + +void SettingsProgressBarWidget::update_progress_bar(int percentage, const std::string& text){ + if (m_progress_bar->isHidden()) { + m_progress_bar->show(); // Make it visible when progress starts + } + m_status_label->setText(QString::fromStdString(text)); + m_progress_bar->setValue(percentage); +} + +void SettingsProgressBarWidget::update_progress_bar(uint64_t bytes_done, uint64_t total_bytes, const std::string& text){ + double percent = total_bytes > 0 ? (static_cast(bytes_done) / total_bytes) * 100.0 : 0; + int current_percent = static_cast(percent); + int last_percentage = m_progress_bar->value(); + // Only update UI if integer value has changed + if (current_percent != last_percentage){ + update_progress_bar(current_percent, text); + } +} + +void SettingsProgressBarWidget::on_download_progress(uint64_t bytes_done, uint64_t total_bytes){ + QMetaObject::invokeMethod(this, [this, bytes_done, total_bytes]{ + update_progress_bar(bytes_done, total_bytes, "Downloading"); + }, Qt::QueuedConnection); + +} +void SettingsProgressBarWidget::on_unzip_progress(uint64_t bytes_done, uint64_t total_bytes){ + QMetaObject::invokeMethod(this, [this, bytes_done, total_bytes]{ + update_progress_bar(bytes_done, total_bytes, "Unzipping"); + }, Qt::QueuedConnection); +} +void SettingsProgressBarWidget::on_hash_progress(uint64_t bytes_done, uint64_t total_bytes){ + QMetaObject::invokeMethod(this, [this, bytes_done, total_bytes]{ + update_progress_bar(bytes_done, total_bytes, "Verifying"); + }, Qt::QueuedConnection); +} +// when action_state_updated, update the UI state to match +void SettingsProgressBarWidget::on_action_state_updated(){ + QMetaObject::invokeMethod(this, [this]{ + update_UI_state(); + }, Qt::QueuedConnection); + +} + + +///////////////////////////////////////////////////////////////////////////////////////////////////////// +// SettingsDownloadErrorWidget +///////////////////////////////////////////////////////////////////////////////////////////////////////// +template class RegisterConfigWidget; +SettingsDownloadErrorWidget::~SettingsDownloadErrorWidget(){ + GlobalResourceDownloadManager::instance().remove_download_listener(*this); +} +SettingsDownloadErrorWidget::SettingsDownloadErrorWidget(QWidget& parent, SettingsDownloadError& value) + : QWidget(&parent) + , ConfigWidget(value, *this) +{ + GlobalResourceDownloadManager::instance().add_download_listener(*this); +} + +void SettingsDownloadErrorWidget::show_download_failed_box(const std::string& resource_slug){ + std::cerr << "SettingsDownloadErrorWidget::show_download_failed_box: Error: Download failed for " << resource_slug << ". Check your internet connection and check you have enough disk space." << std::endl; + if (m_popup_is_open.exchange(true)){ // only show popups if one isn't already open + return; + } + + QMessageBox box; + box.warning(nullptr, "Error:", + QString::fromStdString("Error: Download failed for " + resource_slug + " (and others possibly as well). Check your internet connection and check you have enough disk space.")); + + m_popup_is_open.store(false); +} + +void SettingsDownloadErrorWidget::show_error_box(std::string error_msg){ + std::cerr << "SettingsDownloadErrorWidget::show_error_box: " << error_msg << std::endl; + if (m_popup_is_open.exchange(true)){ + return; + } + QMessageBox box; + box.warning(nullptr, "Error:", + QString::fromStdString(error_msg)); + + m_popup_is_open.store(false); + +} + +// GlobalResourceDownloadManager::Listener +// +void SettingsDownloadErrorWidget::on_download_failed(const std::string& resource_slug){ + QMetaObject::invokeMethod(this, [this, resource_slug]{ + show_download_failed_box(resource_slug); + }, Qt::QueuedConnection); +} +void SettingsDownloadErrorWidget::on_exception_caught(const std::string& error_msg){ + QMetaObject::invokeMethod(this, [this, error_msg]{ + show_error_box(error_msg); + }, Qt::QueuedConnection); +} + +} diff --git a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.h b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.h new file mode 100644 index 0000000000..82f09766d9 --- /dev/null +++ b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.h @@ -0,0 +1,147 @@ +/* Resource Download Widget + * + * From: https://github.com/PokemonAutomation/ + * + */ + +#ifndef PokemonAutomation_SettingsResourceDownloadWidget_H +#define PokemonAutomation_SettingsResourceDownloadWidget_H + +#include +#include +#include +#include "Common/Qt/Options/ConfigWidget.h" +// #include "SettingsResourceDownloadTable.h" +#include "GlobalResourceDownloadManager.h" +#include "SettingsResourceDownloadRow.h" + +namespace PokemonAutomation{ + +// class SettingsResourceDownloadButton; + +class SettingsDownloadButtonWidget : public QWidget, public ConfigWidget, public SettingsResourceDownloadRow::Listener{ + // Q_OBJECT +public: + using ParentOption = SettingsResourceDownloadButton; + +public: + ~SettingsDownloadButtonWidget(); + SettingsDownloadButtonWidget(QWidget& parent, SettingsResourceDownloadButton& value); + + virtual void on_metadata_fetch_finished(const std::string& popup_message) override; + virtual void on_action_state_updated() override; + +private: + void update_UI_state(); + void show_download_confirm_box( + const std::string& title, + const std::string& message_body + ); + +private: + SettingsResourceDownloadButton& m_value; + SettingsResourceDownloadRow& m_row; + QPushButton* m_button; + +}; + +void show_error_box(std::string function_name); + + +class SettingsDeleteButtonWidget : public QWidget, public ConfigWidget, public SettingsResourceDownloadRow::Listener{ +public: + using ParentOption = SettingsResourceDeleteButton; + +public: + ~SettingsDeleteButtonWidget(); + SettingsDeleteButtonWidget(QWidget& parent, SettingsResourceDeleteButton& value); + + virtual void on_action_state_updated() override; + +private: + void update_UI_state(); + void show_delete_confirm_box(); + +private: + SettingsResourceDeleteButton& m_value; + SettingsResourceDownloadRow& m_row; + QPushButton* m_button; +}; + +class SettingsCancelButtonWidget : public QWidget, public ConfigWidget, public SettingsResourceDownloadRow::Listener{ +public: + using ParentOption = SettingsResourceCancelButton; + +public: + ~SettingsCancelButtonWidget(); + SettingsCancelButtonWidget(QWidget& parent, SettingsResourceCancelButton& value); + + virtual void on_action_state_updated() override; + +private: + void update_UI_state(); + void show_cancel_confirm_box(); + +private: + SettingsResourceCancelButton& m_value; + SettingsResourceDownloadRow& m_row; + QPushButton* m_button; +}; + +class SettingsProgressBarWidget : public QWidget, public ConfigWidget, public SettingsResourceDownloadRow::Listener{ +public: + using ParentOption = SettingsResourceProgressBar; + +public: + ~SettingsProgressBarWidget(); + SettingsProgressBarWidget(QWidget& parent, SettingsResourceProgressBar& value); + + virtual void on_download_progress(uint64_t bytes_done, uint64_t total_bytes) override; + virtual void on_unzip_progress(uint64_t bytes_done, uint64_t total_bytes) override; + virtual void on_hash_progress(uint64_t bytes_done, uint64_t total_bytes) override; + + virtual void on_action_state_updated() override; + +private: + void update_UI_state(); + void update_progress_bar(int percentage, const std::string& text); + void update_progress_bar(uint64_t bytes_done, uint64_t total_bytes, const std::string& text); + +private: + // SettingsResourceProgressBar& m_value; + SettingsResourceDownloadRow& m_row; + QLabel* m_status_label; + QProgressBar* m_progress_bar; +}; + +class SettingsDownloadErrorWidget : public QWidget, public ConfigWidget, public GlobalResourceDownloadManager::Listener{ +public: + using ParentOption = SettingsDownloadError; + +public: + ~SettingsDownloadErrorWidget(); + SettingsDownloadErrorWidget(QWidget& parent, SettingsDownloadError& value); + +public: // GlobalResourceDownloadManager::Listener + // virtual void on_all_downloads_finished(){} + virtual void on_download_failed(const std::string& resource_slug) override; + virtual void on_exception_caught(const std::string& error_msg) override; + +private: + // show popup for download failed. Will only show 1 pop-up at a time. + void show_download_failed_box(const std::string& resource_slug); + + // show popup for download error. Will only show 1 pop-up at a time. + void show_error_box(std::string error_msg); + +private: + std::atomic m_popup_is_open{false}; + +}; + + + + + +} +#endif diff --git a/SerialPrograms/cmake/SourceFiles.cmake b/SerialPrograms/cmake/SourceFiles.cmake index 95e9cc92d5..f6e5f3cf92 100644 --- a/SerialPrograms/cmake/SourceFiles.cmake +++ b/SerialPrograms/cmake/SourceFiles.cmake @@ -496,12 +496,20 @@ file(GLOB LIBRARY_SOURCES Source/CommonFramework/Recording/StreamRecorder.h Source/CommonFramework/ResourceDownload/DownloadThread.cpp Source/CommonFramework/ResourceDownload/DownloadThread.h - Source/CommonFramework/ResourceDownload/RequiredDownload.cpp - Source/CommonFramework/ResourceDownload/RequiredDownload.h - Source/CommonFramework/ResourceDownload/RequiredDownloadManager.cpp - Source/CommonFramework/ResourceDownload/RequiredDownloadManager.h + Source/CommonFramework/ResourceDownload/GlobalResourceDownloadManager.cpp + Source/CommonFramework/ResourceDownload/GlobalResourceDownloadManager.h + Source/CommonFramework/ResourceDownload/ResourceDownload.cpp + Source/CommonFramework/ResourceDownload/ResourceDownload.h Source/CommonFramework/ResourceDownload/ResourceDownloadHelpers.cpp Source/CommonFramework/ResourceDownload/ResourceDownloadHelpers.h + Source/CommonFramework/ResourceDownload/SettingsResourceDownloadOptions.cpp + Source/CommonFramework/ResourceDownload/SettingsResourceDownloadOptions.h + Source/CommonFramework/ResourceDownload/SettingsResourceDownloadRow.cpp + Source/CommonFramework/ResourceDownload/SettingsResourceDownloadRow.h + Source/CommonFramework/ResourceDownload/SettingsResourceDownloadTable.cpp + Source/CommonFramework/ResourceDownload/SettingsResourceDownloadTable.h + Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.cpp + Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.h Source/CommonFramework/Startup/NewVersionCheck.cpp Source/CommonFramework/Startup/NewVersionCheck.h Source/CommonFramework/Startup/SetupSettings.cpp From 6f07e194a700e5a7bddd3c5531f32b0e3b2f2f51 Mon Sep 17 00:00:00 2001 From: jw098 Date: Wed, 24 Jun 2026 21:22:45 -0700 Subject: [PATCH 02/10] clean up class members and headers --- .../GlobalResourceDownloadManager.h | 1 - .../SettingsResourceDownloadOptions.cpp | 9 +- .../SettingsResourceDownloadOptions.h | 6 +- .../SettingsResourceDownloadRow.cpp | 132 ++++++++++-------- .../SettingsResourceDownloadRow.h | 20 +-- .../SettingsResourceDownloadTable.cpp | 8 +- .../SettingsResourceDownloadTable.h | 7 +- .../SettingsResourceDownloadWidget.cpp | 4 - .../SettingsResourceDownloadWidget.h | 6 - 9 files changed, 85 insertions(+), 108 deletions(-) diff --git a/SerialPrograms/Source/CommonFramework/ResourceDownload/GlobalResourceDownloadManager.h b/SerialPrograms/Source/CommonFramework/ResourceDownload/GlobalResourceDownloadManager.h index 28b447f450..ed7c413d7b 100644 --- a/SerialPrograms/Source/CommonFramework/ResourceDownload/GlobalResourceDownloadManager.h +++ b/SerialPrograms/Source/CommonFramework/ResourceDownload/GlobalResourceDownloadManager.h @@ -8,7 +8,6 @@ #define PokemonAutomation_ResourceDownloadManager_H #include -#include "Common/Cpp/Concurrency/SpinLock.h" #include "Common/Cpp/Concurrency/Mutex.h" #include "Common/Cpp/Concurrency/ConditionVariable.h" #include "Common/Cpp/ListenerSet.h" diff --git a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadOptions.cpp b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadOptions.cpp index 1dce848211..4bfcb85045 100644 --- a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadOptions.cpp +++ b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadOptions.cpp @@ -1,4 +1,4 @@ -/* Resource Download Row +/* Resource Download Options * * From: https://github.com/PokemonAutomation/ * @@ -7,11 +7,10 @@ #include "SettingsResourceDownloadRow.h" #include "SettingsResourceDownloadOptions.h" -// #include -#include -using std::cout; -using std::endl; +// #include +// using std::cout; +// using std::endl; namespace PokemonAutomation{ diff --git a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadOptions.h b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadOptions.h index 69e76f7e49..5cba96d17f 100644 --- a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadOptions.h +++ b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadOptions.h @@ -1,4 +1,4 @@ -/* Resource Download Row +/* Resource Download Options * * From: https://github.com/PokemonAutomation/ * @@ -7,10 +7,6 @@ #ifndef PokemonAutomation_ResourceDownloadOptions_H #define PokemonAutomation_ResourceDownloadOptions_H -// #include "Common/Cpp/Containers/Pimpl.h" -// #include "Common/Cpp/Concurrency/AsyncTask.h" -// #include "Common/Cpp/Options/StaticTableOption.h" -// #include "ResourceDownloadHelpers.h" namespace PokemonAutomation{ diff --git a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadRow.cpp b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadRow.cpp index cd96852384..f64964aa23 100644 --- a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadRow.cpp +++ b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadRow.cpp @@ -8,13 +8,14 @@ #include "Common/Cpp/Containers/Pimpl.tpp" #include "Common/Cpp/PrettyPrint.h" #include "Common/Cpp/ListenerSet.h" -// #include "Common/Cpp/Exceptions.h" +#include "Common/Cpp/Concurrency/AsyncTask.h" +#include "Common/Cpp/Filesystem.h" +#include "CommonFramework/Options/LabelCellOption.h" #include "CommonFramework/Tools/GlobalThreadPools.h" #include "CommonFramework/Exceptions/OperationFailedException.h" #include "CommonFramework/Logging/Logger.h" #include "CommonFramework/ResourceDownload/GlobalResourceDownloadManager.h" -#include "Common/Cpp/Filesystem.h" -#include "CommonFramework/Options/LabelCellOption.h" +#include "ResourceDownloadHelpers.h" // #include "SettingsResourceDownloadTable.h" #include "SettingsResourceDownloadRow.h" @@ -58,15 +59,17 @@ std::string is_downloaded_string(bool is_downloaded){ struct SettingsResourceDownloadRow::Data{ Data( - std::string& resource_name, - size_t file_size, + DownloadedResourceMetadata expected_metadata, bool is_downloaded, std::optional version_num, ResourceVersionStatus version_status ) - : m_resource_name(LockMode::LOCK_WHILE_RUNNING, resource_name) - , m_file_size(file_size) - , m_file_size_label(LockMode::LOCK_WHILE_RUNNING, tostr_bytes(file_size)) + : m_local_metadata(expected_metadata) + , m_action_state(ActionState::READY) + , m_resource_slug(expected_metadata.resource_name) + , m_resource_name_label(LockMode::LOCK_WHILE_RUNNING, m_resource_slug) + , m_file_size(expected_metadata.size_decompressed_bytes) + , m_file_size_label(LockMode::LOCK_WHILE_RUNNING, tostr_bytes(m_file_size)) , m_is_downloaded(is_downloaded) , m_is_downloaded_label(LockMode::LOCK_WHILE_RUNNING, is_downloaded_string(is_downloaded)) , m_version_num(version_num) @@ -74,9 +77,14 @@ struct SettingsResourceDownloadRow::Data{ , m_version_status_label(LockMode::LOCK_WHILE_RUNNING, resource_version_to_string(version_status)) {} - ListenerSet listeners; - LabelCellOption m_resource_name; + + DownloadedResourceMetadata m_local_metadata; + + ActionState m_action_state; + + std::string m_resource_slug; + LabelCellOption m_resource_name_label; size_t m_file_size; LabelCellOption m_file_size_label; @@ -88,6 +96,19 @@ struct SettingsResourceDownloadRow::Data{ ResourceVersionStatus m_version_status; LabelCellOption m_version_status_label; + AsyncTask m_pre_download_thread; + AsyncTask m_delete_thread; + + std::shared_ptr m_download_ptr; + + std::optional m_cached_metadata; + + Mutex m_action_state_lock; + + + ListenerSet listeners; + + }; @@ -96,6 +117,9 @@ void SettingsResourceDownloadRow::set_version_status(ResourceVersionStatus versi m_data->m_version_status_label.set_text(resource_version_to_string(version_status)); } +std::string SettingsResourceDownloadRow::get_resource_slug(){ + return m_data->m_resource_slug; +} void SettingsResourceDownloadRow::set_is_downloaded(bool is_downloaded){ m_data->m_is_downloaded = is_downloaded; @@ -111,30 +135,26 @@ void SettingsResourceDownloadRow::update_table_label(bool success){ SettingsResourceDownloadRow::~SettingsResourceDownloadRow(){ // cout << "~SettingsResourceDownloadRow" << endl; - if (m_download_ptr) { - m_download_ptr->remove_listener(*this); + if (m_data->m_download_ptr) { + m_data->m_download_ptr->remove_listener(*this); } - m_pre_download_thread.wait_and_ignore_exceptions(); - m_delete_thread.wait_and_ignore_exceptions(); + m_data->m_pre_download_thread.wait_and_ignore_exceptions(); + m_data->m_delete_thread.wait_and_ignore_exceptions(); } SettingsResourceDownloadRow::SettingsResourceDownloadRow( - std::string resource_slug, DownloadedResourceMetadata local_metadata, bool is_downloaded, std::optional version_num, ResourceVersionStatus version_status ) : StaticTableRow(local_metadata.resource_name) - , m_action_state(ActionState::READY) - , m_resource_slug(resource_slug) - , m_local_metadata(local_metadata) - , m_data(CONSTRUCT_TOKEN, local_metadata.resource_name, local_metadata.size_decompressed_bytes, is_downloaded, version_num, version_status) + , m_data(CONSTRUCT_TOKEN, local_metadata, is_downloaded, version_num, version_status) , m_download_button(*this) , m_delete_button(*this) , m_cancel_button(*this) , m_progress_bar(*this) { - PA_ADD_STATIC(m_data->m_resource_name); + PA_ADD_STATIC(m_data->m_resource_name_label); PA_ADD_STATIC(m_data->m_file_size_label); PA_ADD_STATIC(m_data->m_is_downloaded_label); PA_ADD_STATIC(m_data->m_version_status_label); @@ -149,8 +169,8 @@ SettingsResourceDownloadRow::SettingsResourceDownloadRow( const DownloadedResourceMetadata& SettingsResourceDownloadRow::fetch_remote_metadata(){ - if (m_cached_metadata.has_value()){ - return m_cached_metadata.value(); + if (m_data->m_cached_metadata.has_value()){ + return m_data->m_cached_metadata.value(); } Logger& logger = global_logger_tagged(); @@ -164,12 +184,12 @@ const DownloadedResourceMetadata& SettingsResourceDownloadRow::fetch_remote_meta "Error: Download failed. Failed to fetch the list of available downloads. Check your internet connection."); } - std::string resource_name = m_data->m_resource_name.text(); + std::string resource_name = m_data->m_resource_name_label.text(); for (const DownloadedResourceMetadata& remote_metadata : all_remote_metadata){ if (remote_metadata.resource_name == resource_name){ - m_cached_metadata = remote_metadata; - return m_cached_metadata.value(); + m_data->m_cached_metadata = remote_metadata; + return m_data->m_cached_metadata.value(); } } @@ -182,7 +202,7 @@ const DownloadedResourceMetadata& SettingsResourceDownloadRow::fetch_remote_meta void SettingsResourceDownloadRow::ensure_remote_metadata_loaded(){ - m_pre_download_thread = GlobalThreadPools::unlimited_normal().dispatch_now_blocking( + m_data->m_pre_download_thread = GlobalThreadPools::unlimited_normal().dispatch_now_blocking( [this]{ try { if (!is_given_action_state(ActionState::PRE_DOWNLOAD)){ @@ -209,7 +229,7 @@ void SettingsResourceDownloadRow::ensure_remote_metadata_loaded(){ // cout << "failed" << endl; // update_table_label(false); update_action_state(ActionState::READY); - GlobalResourceDownloadManager::instance().report_download_failed(m_resource_slug); + GlobalResourceDownloadManager::instance().report_download_failed(m_data->m_resource_slug); return; }catch(...){ // update_table_label(false); @@ -228,7 +248,7 @@ std::string SettingsResourceDownloadRow::predownload_warning_summary(const Downl std::string predownload_warning; - uint16_t local_version_num = m_local_metadata.version_num.value(); + uint16_t local_version_num = m_data->m_local_metadata.version_num.value(); uint16_t remote_version_num = remote_metadata.version_num.value(); size_t compressed_size = remote_metadata.size_compressed_bytes; @@ -264,7 +284,7 @@ void SettingsResourceDownloadRow::start_download(){ cancel_download_thread(); // cancels old download thread try{ - std::shared_ptr download_ptr = GlobalResourceDownloadManager::instance().add_to_download_list(m_resource_slug); + std::shared_ptr download_ptr = GlobalResourceDownloadManager::instance().add_to_download_list(m_data->m_resource_slug); }catch(OperationFailedException&){ update_action_state(ActionState::READY); @@ -274,7 +294,7 @@ void SettingsResourceDownloadRow::start_download(){ void SettingsResourceDownloadRow::start_delete(){ - m_delete_thread = GlobalThreadPools::unlimited_normal().dispatch_now_blocking( + m_data->m_delete_thread = GlobalThreadPools::unlimited_normal().dispatch_now_blocking( [this]{ try { @@ -287,7 +307,7 @@ void SettingsResourceDownloadRow::start_delete(){ } update_action_state(ActionState::DELETING); - std::string resource_name = m_local_metadata.resource_name; + std::string resource_name = m_data->m_local_metadata.resource_name; std::string resource_directory = DOWNLOADED_RESOURCE_PATH() + resource_name; // delete directory and the old resource @@ -317,70 +337,70 @@ void SettingsResourceDownloadRow::start_delete(){ void SettingsResourceDownloadRow::update_action_state(ActionState state){ - std::lock_guard lock(m_action_state_lock); + std::lock_guard lock(m_data->m_action_state_lock); { switch (state){ case ActionState::PRE_DOWNLOAD: // action state can only enter the PRE_DOWNLOAD state // if going from the READY state - if (m_action_state == ActionState::READY){ + if (m_data->m_action_state == ActionState::READY){ m_download_button.set_enabled(false); m_delete_button.set_enabled(false); m_cancel_button.set_enabled(true); - m_action_state = state; + m_data->m_action_state = state; cout << "ActionState::PRE_DOWNLOAD" << endl; } break; case ActionState::DOWNLOADING: - if (m_action_state == ActionState::PRE_DOWNLOAD || m_action_state == ActionState::PRE_CANCEL || m_action_state == ActionState::READY){ + if (m_data->m_action_state == ActionState::PRE_DOWNLOAD || m_data->m_action_state == ActionState::PRE_CANCEL || m_data->m_action_state == ActionState::READY){ m_download_button.set_enabled(false); m_delete_button.set_enabled(false); m_cancel_button.set_enabled(true); - m_action_state = state; + m_data->m_action_state = state; cout << "ActionState::DOWNLOADING" << endl; } break; case ActionState::PRE_DELETE: // action state can only enter the PRE_DELETE state // if going from the READY state - if (m_action_state == ActionState::READY){ + if (m_data->m_action_state == ActionState::READY){ m_download_button.set_enabled(false); m_delete_button.set_enabled(false); m_cancel_button.set_enabled(false); - m_action_state = state; + m_data->m_action_state = state; cout << "ActionState::PRE_DELETE" << endl; } break; case ActionState::DELETING: // action state can only enter the DELETING state // if going from the PRE_DELETE state - if (m_action_state == ActionState::PRE_DELETE){ + if (m_data->m_action_state == ActionState::PRE_DELETE){ m_download_button.set_enabled(false); m_delete_button.set_enabled(false); m_cancel_button.set_enabled(false); - m_action_state = state; + m_data->m_action_state = state; cout << "ActionState::DELETING" << endl; } break; case ActionState::PRE_CANCEL: // action state can only enter the PRE_CANCEL state // if going from the DOWNLOADING state - if (m_action_state == ActionState::DOWNLOADING){ + if (m_data->m_action_state == ActionState::DOWNLOADING){ m_download_button.set_enabled(false); m_delete_button.set_enabled(false); m_cancel_button.set_enabled(false); - m_action_state = state; + m_data->m_action_state = state; cout << "ActionState::PRE_CANCEL" << endl; } break; case ActionState::CANCELLING: // action state can only enter the CANCELLING state // if going from the PRE_CANCEL state - if (m_action_state == ActionState::PRE_CANCEL){ + if (m_data->m_action_state == ActionState::PRE_CANCEL){ m_download_button.set_enabled(false); m_delete_button.set_enabled(false); m_cancel_button.set_enabled(false); - m_action_state = state; + m_data->m_action_state = state; cout << "ActionState::CANCELLING" << endl; } break; @@ -388,7 +408,7 @@ void SettingsResourceDownloadRow::update_action_state(ActionState state){ m_download_button.set_enabled(true); m_delete_button.set_enabled(true); m_cancel_button.set_enabled(true); - m_action_state = state; + m_data->m_action_state = state; cout << "ActionState::READY" << endl; break; default: @@ -400,28 +420,28 @@ void SettingsResourceDownloadRow::update_action_state(ActionState state){ } ActionState SettingsResourceDownloadRow::get_action_state(){ - std::lock_guard lock(m_action_state_lock); - return m_action_state; + std::lock_guard lock(m_data->m_action_state_lock); + return m_data->m_action_state; } bool SettingsResourceDownloadRow::is_given_action_state(ActionState state){ - std::lock_guard lock(m_action_state_lock); - return m_action_state == state; + std::lock_guard lock(m_data->m_action_state_lock); + return m_data->m_action_state == state; } void SettingsResourceDownloadRow::cancel_download_thread(){ - if (m_download_ptr){ // if download is active - m_download_ptr->cancel_download(); + if (m_data->m_download_ptr){ // if download is active + m_data->m_download_ptr->cancel_download(); } } void SettingsResourceDownloadRow::connect_with_download(std::shared_ptr download_ptr){ - if (m_download_ptr){ - m_download_ptr->remove_listener(*this); + if (m_data->m_download_ptr){ + m_data->m_download_ptr->remove_listener(*this); } - m_download_ptr = std::move(download_ptr); - m_download_ptr->add_listener(*this); + m_data->m_download_ptr = std::move(download_ptr); + m_data->m_download_ptr->add_listener(*this); update_action_state(ActionState::DOWNLOADING); } @@ -478,7 +498,7 @@ void SettingsResourceDownloadRow::on_hash_progress(uint64_t bytes_done, uint64_t void SettingsResourceDownloadRow::on_download_finished(bool success, const std::string& resource_slug){ // we can't run `download_ptr->remove_listener(*this)` in this function // since it results in deadlock, since this function is part of the listener loop - m_download_ptr.reset(); + m_data->m_download_ptr.reset(); update_action_state(ActionState::READY); update_table_label(success); diff --git a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadRow.h b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadRow.h index 459da9e2f1..4241e813bf 100644 --- a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadRow.h +++ b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadRow.h @@ -8,15 +8,10 @@ #define PokemonAutomation_ResourceDownloadRow_H #include "Common/Cpp/Containers/Pimpl.h" -#include "Common/Cpp/Concurrency/AsyncTask.h" -// #include "Common/Cpp/Concurrency/ConditionVariable.h" #include "Common/Cpp/LifetimeSanitizer.h" -// #include "CommonFramework/Tools/GlobalThreadPools.h" #include "Common/Cpp/Options/StaticTableOption.h" -#include "ResourceDownloadHelpers.h" #include "ResourceDownload.h" #include "SettingsResourceDownloadOptions.h" -// #include namespace PokemonAutomation{ @@ -34,7 +29,6 @@ class SettingsResourceDownloadRow : public StaticTableRow, public ResourceDownlo public: ~SettingsResourceDownloadRow(); SettingsResourceDownloadRow( - std::string resource_slug, DownloadedResourceMetadata local_metadata, bool is_downloaded, std::optional version_num, @@ -72,7 +66,7 @@ class SettingsResourceDownloadRow : public StaticTableRow, public ResourceDownlo virtual void on_download_finished(bool success, const std::string& resource_slug) override; public: - std::string get_resource_slug(){ return m_resource_slug; } + std::string get_resource_slug(); void set_version_status(ResourceVersionStatus version_status); void set_is_downloaded(bool is_downloaded); void update_table_label(bool success); @@ -104,9 +98,6 @@ class SettingsResourceDownloadRow : public StaticTableRow, public ResourceDownlo void connect_with_download(std::shared_ptr download_ptr); private: - ActionState m_action_state; - std::string m_resource_slug; - DownloadedResourceMetadata m_local_metadata; struct Data; Pimpl m_data; @@ -115,15 +106,6 @@ class SettingsResourceDownloadRow : public StaticTableRow, public ResourceDownlo SettingsResourceCancelButton m_cancel_button; SettingsResourceProgressBar m_progress_bar; - AsyncTask m_pre_download_thread; - AsyncTask m_delete_thread; - - std::optional m_cached_metadata; - - std::shared_ptr m_download_ptr; - - Mutex m_action_state_lock; - LifetimeSanitizer m_lifetime_sanitizer; diff --git a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadTable.cpp b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadTable.cpp index 84d9505cd9..5ef91e1782 100644 --- a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadTable.cpp +++ b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadTable.cpp @@ -6,12 +6,6 @@ #include "CommonFramework/Globals.h" #include "Common/Cpp/Exceptions.h" -// #include "CommonFramework/Logging/Logger.h" -// #include "CommonFramework/Tools/GlobalThreadPools.h" -// #include "CommonFramework/Tools/FileDownloader.h" -// #include "CommonFramework/Exceptions/OperationFailedException.h" -// #include "Common/Cpp/Json/JsonArray.h" -// #include "Common/Cpp/Json/JsonObject.h" #include "Common/Cpp/Filesystem.h" #include "ResourceDownload.h" #include "SettingsResourceDownloadRow.h" @@ -43,7 +37,7 @@ std::vector> SettingsResourceDownlo auto [is_downloaded, version_status, current_version_num] = get_local_version_info(resource_name); - resource_rows.emplace_back(std::make_unique(resource_name, resource, is_downloaded, current_version_num, version_status)); + resource_rows.emplace_back(std::make_unique(resource, is_downloaded, current_version_num, version_status)); } return resource_rows; diff --git a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadTable.h b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadTable.h index 307deca070..4c346f43c4 100644 --- a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadTable.h +++ b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadTable.h @@ -7,10 +7,6 @@ #ifndef PokemonAutomation_ResourceDownloadTable_H #define PokemonAutomation_ResourceDownloadTable_H -#include -#include "Common/Cpp/Concurrency/AsyncTask.h" -#include "Common/Cpp/Concurrency/Mutex.h" -#include "Common/Cpp/Concurrency/ConditionVariable.h" #include "Common/Cpp/Options/StaticTableOption.h" // #include "SettingsResourceDownloadRow.h" @@ -34,7 +30,8 @@ class SettingsResourceDownloadTable : public StaticTableOption{ private: - // we need to keep a handle on each Row, so that we can edit m_is_downloaded_label later on. + // must use a vector of pointers to the Row, since the Row class contains a mutex + // and so can't be moved std::vector> m_resource_rows; }; diff --git a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.cpp b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.cpp index 5c4d05fed5..693d663e97 100644 --- a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.cpp +++ b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.cpp @@ -5,15 +5,11 @@ */ #include -#include #include #include -#include #include #include "CommonFramework/Logging/Logger.h" #include "Common/Cpp/Exceptions.h" - -#include "CommonFramework/Notifications/ProgramNotifications.h" #include "SettingsResourceDownloadWidget.h" #include diff --git a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.h b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.h index 82f09766d9..b4cd340da1 100644 --- a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.h +++ b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.h @@ -7,20 +7,16 @@ #ifndef PokemonAutomation_SettingsResourceDownloadWidget_H #define PokemonAutomation_SettingsResourceDownloadWidget_H -#include #include #include #include "Common/Qt/Options/ConfigWidget.h" -// #include "SettingsResourceDownloadTable.h" #include "GlobalResourceDownloadManager.h" #include "SettingsResourceDownloadRow.h" namespace PokemonAutomation{ -// class SettingsResourceDownloadButton; class SettingsDownloadButtonWidget : public QWidget, public ConfigWidget, public SettingsResourceDownloadRow::Listener{ - // Q_OBJECT public: using ParentOption = SettingsResourceDownloadButton; @@ -45,8 +41,6 @@ class SettingsDownloadButtonWidget : public QWidget, public ConfigWidget, public }; -void show_error_box(std::string function_name); - class SettingsDeleteButtonWidget : public QWidget, public ConfigWidget, public SettingsResourceDownloadRow::Listener{ public: From be2fe4c66b31964560b547cdbd67a285923e6bef Mon Sep 17 00:00:00 2001 From: jw098 Date: Fri, 26 Jun 2026 18:15:52 -0700 Subject: [PATCH 03/10] refactor listeners for Download Row options --- .../SettingsResourceDownloadOptions.cpp | 47 +++++++++- .../SettingsResourceDownloadOptions.h | 37 +++++--- .../SettingsResourceDownloadWidget.cpp | 86 +++---------------- .../SettingsResourceDownloadWidget.h | 30 ++++--- 4 files changed, 99 insertions(+), 101 deletions(-) diff --git a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadOptions.cpp b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadOptions.cpp index 4bfcb85045..7bc67cba15 100644 --- a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadOptions.cpp +++ b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadOptions.cpp @@ -14,6 +14,23 @@ namespace PokemonAutomation{ + + +void SettingsResourceButton::add_listener(Listener& listener){ + m_listeners.add(listener); +} +void SettingsResourceButton::remove_listener(Listener& listener){ + m_listeners.remove(listener); +} + +void SettingsResourceButton::change_text(const std::string& text){ + m_listeners.run_method(&Listener::on_change_text, text); +} + + +////////////////////////////////////// +// SettingsResourceDownloadButton +////////////////////////////////////// // SettingsResourceDownloadButton::~SettingsResourceDownloadButton(){} SettingsResourceDownloadButton::SettingsResourceDownloadButton(SettingsResourceDownloadRow& p_row) : ConfigOptionImpl(LockMode::UNLOCK_WHILE_RUNNING) @@ -21,27 +38,53 @@ SettingsResourceDownloadButton::SettingsResourceDownloadButton(SettingsResourceD , m_enabled(true) {} +void SettingsResourceDownloadButton::set_enabled(bool enabled){ + m_enabled = enabled; + change_text(enabled ? "Download" : "Downloading..."); + set_visibility(enabled ? ConfigOptionState::ENABLED : ConfigOptionState::DISABLED); +} + +////////////////////////////////////// +// SettingsResourceDeleteButton +////////////////////////////////////// SettingsResourceDeleteButton::SettingsResourceDeleteButton(SettingsResourceDownloadRow& p_row) : ConfigOptionImpl(LockMode::UNLOCK_WHILE_RUNNING) , row(p_row) , m_enabled(true) {} +void SettingsResourceDeleteButton::set_enabled(bool enabled){ + m_enabled = enabled; + change_text(enabled ? "Delete" : "Deleting..."); + set_visibility(enabled ? ConfigOptionState::ENABLED : ConfigOptionState::DISABLED); +} +////////////////////////////////////// +// SettingsResourceCancelButton +////////////////////////////////////// SettingsResourceCancelButton::SettingsResourceCancelButton(SettingsResourceDownloadRow& p_row) : ConfigOptionImpl(LockMode::UNLOCK_WHILE_RUNNING) , row(p_row) , m_enabled(true) {} - +void SettingsResourceCancelButton::set_enabled(bool enabled){ + m_enabled = enabled; + change_text(enabled ? "Cancel" : "Cancelling..."); + set_visibility(enabled ? ConfigOptionState::ENABLED : ConfigOptionState::DISABLED); +} +////////////////////////////////////// +// SettingsResourceProgressBar +////////////////////////////////////// SettingsResourceProgressBar::SettingsResourceProgressBar(SettingsResourceDownloadRow& p_row) : ConfigOptionImpl(LockMode::UNLOCK_WHILE_RUNNING) , row(p_row) {} - +////////////////////////////////////// +// SettingsDownloadError +////////////////////////////////////// SettingsDownloadError::SettingsDownloadError() : ConfigOptionImpl(LockMode::LOCK_WHILE_RUNNING) {} diff --git a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadOptions.h b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadOptions.h index 5cba96d17f..35ea41dad0 100644 --- a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadOptions.h +++ b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadOptions.h @@ -7,23 +7,37 @@ #ifndef PokemonAutomation_ResourceDownloadOptions_H #define PokemonAutomation_ResourceDownloadOptions_H - +#include "Common/Cpp/ListenerSet.h" namespace PokemonAutomation{ class SettingsResourceDownloadRow; -class SettingsResourceDownloadButton : public ConfigOptionImpl{ +class SettingsResourceButton { +public: + struct Listener{ + virtual void on_change_text(const std::string& text){} + }; + + void add_listener(Listener& listener); + void remove_listener(Listener& listener); + + void change_text(const std::string& text); + +private: + ListenerSet m_listeners; + +}; + +class SettingsResourceDownloadButton : public ConfigOptionImpl, public SettingsResourceButton{ public: // ~SettingsResourceDownloadButton(); SettingsResourceDownloadButton(SettingsResourceDownloadRow& p_row); public: inline bool get_enabled(){ return m_enabled; } - inline void set_enabled(bool enabled){ - m_enabled = enabled; - } + void set_enabled(bool enabled); public: SettingsResourceDownloadRow& row; @@ -32,19 +46,16 @@ class SettingsResourceDownloadButton : public ConfigOptionImpl{ +class SettingsResourceDeleteButton : public ConfigOptionImpl, public SettingsResourceButton{ public: SettingsResourceDeleteButton(SettingsResourceDownloadRow& p_row); public: inline bool get_enabled(){ return m_enabled; } - inline void set_enabled(bool enabled){ - m_enabled = enabled; - } + void set_enabled(bool enabled); public: SettingsResourceDownloadRow& row; @@ -53,15 +64,13 @@ class SettingsResourceDeleteButton : public ConfigOptionImpl{ +class SettingsResourceCancelButton : public ConfigOptionImpl, public SettingsResourceButton{ public: SettingsResourceCancelButton(SettingsResourceDownloadRow& p_row); public: inline bool get_enabled(){ return m_enabled; } - inline void set_enabled(bool enabled){ - m_enabled = enabled; - } + void set_enabled(bool enabled); public: SettingsResourceDownloadRow& row; diff --git a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.cpp b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.cpp index 693d663e97..2988109a1a 100644 --- a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.cpp +++ b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.cpp @@ -55,15 +55,6 @@ SettingsDownloadButtonWidget::SettingsDownloadButtonWidget(QWidget& parent, Sett int minWidth = metrics.horizontalAdvance("Downloading..."); m_button->setMinimumWidth(minWidth); - // Button should be disabled when in the middle of downloading - // this status is stored within SettingsResourceDownloadButton::m_enabled - // when the button is clicked, m_enabled is set to false - // when te download is done, m_enabled is set back to true - // the UI is updated to reflect the status of m_enabled, by using update_UI_state - - - // update the UI based on m_enabled, when the button is constructed - update_UI_state(); // when the button is clicked, runs row.update_action_state(), which updates the button state // also, fetch json @@ -83,18 +74,10 @@ SettingsDownloadButtonWidget::SettingsDownloadButtonWidget(QWidget& parent, Sett } -void SettingsDownloadButtonWidget::update_UI_state(){ - if (m_value.get_enabled()){ - m_button->setEnabled(true); - m_button->setText("Download"); - }else{ - m_button->setEnabled(false); - if (m_row.is_given_action_state(ActionState::PRE_DOWNLOAD) - || m_row.is_given_action_state(ActionState::DOWNLOADING)) - { - m_button->setText("Downloading..."); - } - } +void SettingsDownloadButtonWidget::on_change_text(const std::string& text){ + QMetaObject::invokeMethod(this, [this, text]{ + m_button->setText(QString::fromStdString(text)); + }, Qt::QueuedConnection); } @@ -146,11 +129,6 @@ void SettingsDownloadButtonWidget::on_metadata_fetch_finished(const std::string& } -void SettingsDownloadButtonWidget::on_action_state_updated(){ - QMetaObject::invokeMethod(this, [this]{ - update_UI_state(); - }, Qt::QueuedConnection); -} ///////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -186,9 +164,6 @@ SettingsDeleteButtonWidget::SettingsDeleteButtonWidget(QWidget& parent, Settings m_button->setMinimumWidth(minWidth); - // update the UI based on m_enabled, when the button is constructed - update_UI_state(); - // when the button is clicked, runs row.update_action_state(), which updates the button state // also, show the delete confirm box connect( @@ -206,19 +181,10 @@ SettingsDeleteButtonWidget::SettingsDeleteButtonWidget(QWidget& parent, Settings m_row.add_listener(*this); } - -void SettingsDeleteButtonWidget::update_UI_state(){ - if (m_value.get_enabled()){ - m_button->setEnabled(true); - m_button->setText("Delete"); - }else{ - m_button->setEnabled(false); - if (m_row.is_given_action_state(ActionState::PRE_DELETE) - || m_row.is_given_action_state(ActionState::DELETING) - ){ - m_button->setText("Deleting..."); - } - } +void SettingsDeleteButtonWidget::on_change_text(const std::string& text){ + QMetaObject::invokeMethod(this, [this, text]{ + m_button->setText(QString::fromStdString(text)); + }, Qt::QueuedConnection); } @@ -255,13 +221,6 @@ void SettingsDeleteButtonWidget::show_delete_confirm_box(){ } } -// when action_state_updated, update the UI state to match -void SettingsDeleteButtonWidget::on_action_state_updated(){ - QMetaObject::invokeMethod(this, [this]{ - update_UI_state(); - }, Qt::QueuedConnection); - -} ///////////////////////////////////////////////////////////////////////////////////////////////////////// // SettingsCancelButtonWidget @@ -295,9 +254,6 @@ SettingsCancelButtonWidget::SettingsCancelButtonWidget(QWidget& parent, Settings int minWidth = metrics.horizontalAdvance("Cancelling..."); m_button->setMinimumWidth(minWidth); - // update the UI based on m_enabled, when the button is constructed - update_UI_state(); - // when the button is clicked, runs row.update_action_state(), which updates the button state // also, set cancel state to true connect( @@ -316,6 +272,12 @@ SettingsCancelButtonWidget::SettingsCancelButtonWidget(QWidget& parent, Settings } +void SettingsCancelButtonWidget::on_change_text(const std::string& text){ + QMetaObject::invokeMethod(this, [this, text]{ + m_button->setText(QString::fromStdString(text)); + }, Qt::QueuedConnection); +} + void SettingsCancelButtonWidget::show_cancel_confirm_box(){ QMessageBox box; QPushButton* yes = box.addButton(QMessageBox::Yes); @@ -363,26 +325,6 @@ void SettingsCancelButtonWidget::show_cancel_confirm_box(){ } -void SettingsCancelButtonWidget::update_UI_state(){ - if (m_value.get_enabled()){ - m_button->setEnabled(true); - m_button->setText("Cancel"); - }else{ - m_button->setEnabled(false); - if (m_row.is_given_action_state(ActionState::PRE_CANCEL) - || m_row.is_given_action_state(ActionState::CANCELLING) - ){ - m_button->setText("Cancelling..."); - } - } -} - -// when action_state_updated, update the UI state to match -void SettingsCancelButtonWidget::on_action_state_updated(){ - QMetaObject::invokeMethod(this, [this]{ - update_UI_state(); - }, Qt::QueuedConnection); -} ///////////////////////////////////////////////////////////////////////////////////////////////////////// // SettingsProgressBarWidget diff --git a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.h b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.h index b4cd340da1..71ddfca1e7 100644 --- a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.h +++ b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.h @@ -16,7 +16,7 @@ namespace PokemonAutomation{ -class SettingsDownloadButtonWidget : public QWidget, public ConfigWidget, public SettingsResourceDownloadRow::Listener{ +class SettingsDownloadButtonWidget : public QWidget, public ConfigWidget, public SettingsResourceDownloadRow::Listener, SettingsResourceButton::Listener{ public: using ParentOption = SettingsResourceDownloadButton; @@ -24,11 +24,13 @@ class SettingsDownloadButtonWidget : public QWidget, public ConfigWidget, public ~SettingsDownloadButtonWidget(); SettingsDownloadButtonWidget(QWidget& parent, SettingsResourceDownloadButton& value); +public: // SettingsResourceDownloadRow::Listener virtual void on_metadata_fetch_finished(const std::string& popup_message) override; - virtual void on_action_state_updated() override; + +public: // SettingsResourceButton::Listener + virtual void on_change_text(const std::string& text) override; private: - void update_UI_state(); void show_download_confirm_box( const std::string& title, const std::string& message_body @@ -42,7 +44,7 @@ class SettingsDownloadButtonWidget : public QWidget, public ConfigWidget, public }; -class SettingsDeleteButtonWidget : public QWidget, public ConfigWidget, public SettingsResourceDownloadRow::Listener{ +class SettingsDeleteButtonWidget : public QWidget, public ConfigWidget, public SettingsResourceDownloadRow::Listener, SettingsResourceButton::Listener{ public: using ParentOption = SettingsResourceDeleteButton; @@ -50,19 +52,20 @@ class SettingsDeleteButtonWidget : public QWidget, public ConfigWidget, public ~SettingsDeleteButtonWidget(); SettingsDeleteButtonWidget(QWidget& parent, SettingsResourceDeleteButton& value); - virtual void on_action_state_updated() override; -private: - void update_UI_state(); +private: // SettingsResourceDownloadRow::Listener void show_delete_confirm_box(); +public: // SettingsResourceButton::Listener + virtual void on_change_text(const std::string& text) override; + private: SettingsResourceDeleteButton& m_value; SettingsResourceDownloadRow& m_row; - QPushButton* m_button; + QPushButton* m_button; }; -class SettingsCancelButtonWidget : public QWidget, public ConfigWidget, public SettingsResourceDownloadRow::Listener{ +class SettingsCancelButtonWidget : public QWidget, public ConfigWidget, public SettingsResourceDownloadRow::Listener, SettingsResourceButton::Listener{ public: using ParentOption = SettingsResourceCancelButton; @@ -70,16 +73,17 @@ class SettingsCancelButtonWidget : public QWidget, public ConfigWidget, public ~SettingsCancelButtonWidget(); SettingsCancelButtonWidget(QWidget& parent, SettingsResourceCancelButton& value); - virtual void on_action_state_updated() override; -private: - void update_UI_state(); +private: // SettingsResourceDownloadRow::Listener void show_cancel_confirm_box(); +public: // SettingsResourceButton::Listener + virtual void on_change_text(const std::string& text) override; + private: SettingsResourceCancelButton& m_value; SettingsResourceDownloadRow& m_row; - QPushButton* m_button; + QPushButton* m_button; }; class SettingsProgressBarWidget : public QWidget, public ConfigWidget, public SettingsResourceDownloadRow::Listener{ From 8bc376283f20c325311a2a0bc9ee1b0f9a8e0b8f Mon Sep 17 00:00:00 2001 From: jw098 Date: Sat, 27 Jun 2026 15:06:19 -0700 Subject: [PATCH 04/10] refactor listeners for download widget --- .../SettingsResourceDownloadOptions.cpp | 42 +++++++++- .../SettingsResourceDownloadOptions.h | 31 ++++++- .../SettingsResourceDownloadRow.cpp | 14 ++++ .../SettingsResourceDownloadWidget.cpp | 82 ++++++------------- .../SettingsResourceDownloadWidget.h | 20 ++--- 5 files changed, 115 insertions(+), 74 deletions(-) diff --git a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadOptions.cpp b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadOptions.cpp index 7bc67cba15..3697fcca35 100644 --- a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadOptions.cpp +++ b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadOptions.cpp @@ -16,10 +16,10 @@ namespace PokemonAutomation{ -void SettingsResourceButton::add_listener(Listener& listener){ +void SettingsResourceButton::add_button_listener(Listener& listener){ m_listeners.add(listener); } -void SettingsResourceButton::remove_listener(Listener& listener){ +void SettingsResourceButton::remove_button_listener(Listener& listener){ m_listeners.remove(listener); } @@ -82,6 +82,44 @@ SettingsResourceProgressBar::SettingsResourceProgressBar(SettingsResourceDownloa , row(p_row) {} +void SettingsResourceProgressBar::add_progress_listener(Listener& listener){ + m_listeners.add(listener); +} +void SettingsResourceProgressBar::remove_progress_listener(Listener& listener){ + m_listeners.remove(listener); +} + +void SettingsResourceProgressBar::change_text(const std::string& text){ + m_listeners.run_method(&Listener::on_change_text, text); +} + +void SettingsResourceProgressBar::update_progress(uint64_t bytes_done, uint64_t total_bytes){ + m_listeners.run_method(&Listener::on_update_progress, bytes_done, total_bytes); +} + +void SettingsResourceProgressBar::reset_progress(){ + m_listeners.run_method(&Listener::on_reset_progress); +} + +//////////////////////////////// +// ResourceDownload::Listener +//////////////////////////////// +void SettingsResourceProgressBar::on_download_progress(uint64_t bytes_done, uint64_t total_bytes){ + change_text("Downloading"); + set_visibility(ConfigOptionState::ENABLED); + update_progress(bytes_done, total_bytes); +} +void SettingsResourceProgressBar::on_unzip_progress(uint64_t bytes_done, uint64_t total_bytes){ + change_text("Unzipping"); + set_visibility(ConfigOptionState::ENABLED); + update_progress(bytes_done, total_bytes); +} +void SettingsResourceProgressBar::on_hash_progress(uint64_t bytes_done, uint64_t total_bytes){ + change_text("Verifying"); + set_visibility(ConfigOptionState::ENABLED); + update_progress(bytes_done, total_bytes); +} + ////////////////////////////////////// // SettingsDownloadError ////////////////////////////////////// diff --git a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadOptions.h b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadOptions.h index 35ea41dad0..df85627241 100644 --- a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadOptions.h +++ b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadOptions.h @@ -8,6 +8,7 @@ #define PokemonAutomation_ResourceDownloadOptions_H #include "Common/Cpp/ListenerSet.h" +#include "ResourceDownload.h" namespace PokemonAutomation{ @@ -20,8 +21,8 @@ class SettingsResourceButton { virtual void on_change_text(const std::string& text){} }; - void add_listener(Listener& listener); - void remove_listener(Listener& listener); + void add_button_listener(Listener& listener); + void remove_button_listener(Listener& listener); void change_text(const std::string& text); @@ -79,11 +80,35 @@ class SettingsResourceCancelButton : public ConfigOptionImpl{ +class SettingsResourceProgressBar : public ConfigOptionImpl, public ResourceDownload::Listener{ public: SettingsResourceProgressBar(SettingsResourceDownloadRow& p_row); +public: + struct Listener{ + virtual void on_change_text(const std::string& text){} + virtual void on_update_progress(uint64_t bytes_done, uint64_t total_bytes){} + virtual void on_reset_progress(){} + }; + + void add_progress_listener(Listener& listener); + void remove_progress_listener(Listener& listener); + + void change_text(const std::string& text); + void update_progress(uint64_t bytes_done, uint64_t total_bytes); + void reset_progress(); + +public: // ResourceDownload::Listener + virtual void on_download_progress(uint64_t bytes_done, uint64_t total_bytes) override; + virtual void on_unzip_progress(uint64_t bytes_done, uint64_t total_bytes) override; + virtual void on_hash_progress(uint64_t bytes_done, uint64_t total_bytes) override; + +public: SettingsResourceDownloadRow& row; + +private: + ListenerSet m_listeners; + }; diff --git a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadRow.cpp b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadRow.cpp index f64964aa23..7893be747c 100644 --- a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadRow.cpp +++ b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadRow.cpp @@ -163,6 +163,8 @@ SettingsResourceDownloadRow::SettingsResourceDownloadRow( PA_ADD_STATIC(m_delete_button); PA_ADD_STATIC(m_cancel_button); PA_ADD_STATIC(m_progress_bar); + + update_action_state(ActionState::READY); } @@ -347,6 +349,8 @@ void SettingsResourceDownloadRow::update_action_state(ActionState state){ m_download_button.set_enabled(false); m_delete_button.set_enabled(false); m_cancel_button.set_enabled(true); + m_progress_bar.change_text("Downloading"); + m_progress_bar.set_visibility(ConfigOptionState::ENABLED); m_data->m_action_state = state; cout << "ActionState::PRE_DOWNLOAD" << endl; } @@ -356,6 +360,8 @@ void SettingsResourceDownloadRow::update_action_state(ActionState state){ m_download_button.set_enabled(false); m_delete_button.set_enabled(false); m_cancel_button.set_enabled(true); + m_progress_bar.change_text("Downloading"); + m_progress_bar.set_visibility(ConfigOptionState::ENABLED); m_data->m_action_state = state; cout << "ActionState::DOWNLOADING" << endl; } @@ -367,6 +373,7 @@ void SettingsResourceDownloadRow::update_action_state(ActionState state){ m_download_button.set_enabled(false); m_delete_button.set_enabled(false); m_cancel_button.set_enabled(false); + m_progress_bar.reset_progress(); m_data->m_action_state = state; cout << "ActionState::PRE_DELETE" << endl; } @@ -378,6 +385,7 @@ void SettingsResourceDownloadRow::update_action_state(ActionState state){ m_download_button.set_enabled(false); m_delete_button.set_enabled(false); m_cancel_button.set_enabled(false); + m_progress_bar.reset_progress(); m_data->m_action_state = state; cout << "ActionState::DELETING" << endl; } @@ -389,6 +397,7 @@ void SettingsResourceDownloadRow::update_action_state(ActionState state){ m_download_button.set_enabled(false); m_delete_button.set_enabled(false); m_cancel_button.set_enabled(false); + m_progress_bar.reset_progress(); m_data->m_action_state = state; cout << "ActionState::PRE_CANCEL" << endl; } @@ -400,6 +409,7 @@ void SettingsResourceDownloadRow::update_action_state(ActionState state){ m_download_button.set_enabled(false); m_delete_button.set_enabled(false); m_cancel_button.set_enabled(false); + m_progress_bar.reset_progress(); m_data->m_action_state = state; cout << "ActionState::CANCELLING" << endl; } @@ -408,6 +418,9 @@ void SettingsResourceDownloadRow::update_action_state(ActionState state){ m_download_button.set_enabled(true); m_delete_button.set_enabled(true); m_cancel_button.set_enabled(true); + m_progress_bar.change_text(""); + m_progress_bar.set_visibility(ConfigOptionState::HIDDEN); + m_progress_bar.reset_progress(); m_data->m_action_state = state; cout << "ActionState::READY" << endl; break; @@ -442,6 +455,7 @@ void SettingsResourceDownloadRow::connect_with_download(std::shared_ptrm_download_ptr = std::move(download_ptr); m_data->m_download_ptr->add_listener(*this); + m_data->m_download_ptr->add_listener(m_progress_bar); update_action_state(ActionState::DOWNLOADING); } diff --git a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.cpp b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.cpp index 2988109a1a..3e7cb3bebd 100644 --- a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.cpp +++ b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.cpp @@ -28,6 +28,7 @@ SettingsDownloadButtonWidget::~SettingsDownloadButtonWidget(){ // cout << "Destructor for SettingsDownloadButtonWidget" << endl; // m_value.disconnect(this); m_row.remove_listener(*this); + m_value.remove_button_listener(*this); } SettingsDownloadButtonWidget::SettingsDownloadButtonWidget(QWidget& parent, SettingsResourceDownloadButton& value) : QWidget(&parent) @@ -71,6 +72,7 @@ SettingsDownloadButtonWidget::SettingsDownloadButtonWidget(QWidget& parent, Sett m_row.add_listener(*this); + value.add_button_listener(*this); } @@ -138,6 +140,7 @@ void SettingsDownloadButtonWidget::on_metadata_fetch_finished(const std::string& template class RegisterConfigWidget; SettingsDeleteButtonWidget::~SettingsDeleteButtonWidget(){ m_row.remove_listener(*this); + m_value.remove_button_listener(*this); } SettingsDeleteButtonWidget::SettingsDeleteButtonWidget(QWidget& parent, SettingsResourceDeleteButton& value) : QWidget(&parent) @@ -179,6 +182,7 @@ SettingsDeleteButtonWidget::SettingsDeleteButtonWidget(QWidget& parent, Settings ); m_row.add_listener(*this); + value.add_button_listener(*this); } void SettingsDeleteButtonWidget::on_change_text(const std::string& text){ @@ -229,6 +233,7 @@ void SettingsDeleteButtonWidget::show_delete_confirm_box(){ template class RegisterConfigWidget; SettingsCancelButtonWidget::~SettingsCancelButtonWidget(){ m_row.remove_listener(*this); + m_value.remove_button_listener(*this); } SettingsCancelButtonWidget::SettingsCancelButtonWidget(QWidget& parent, SettingsResourceCancelButton& value) : QWidget(&parent) @@ -269,7 +274,7 @@ SettingsCancelButtonWidget::SettingsCancelButtonWidget(QWidget& parent, Settings ); m_row.add_listener(*this); - + value.add_button_listener(*this); } void SettingsCancelButtonWidget::on_change_text(const std::string& text){ @@ -333,12 +338,12 @@ void SettingsCancelButtonWidget::show_cancel_confirm_box(){ template class RegisterConfigWidget; SettingsProgressBarWidget::~SettingsProgressBarWidget(){ // cout << "Destructor for SettingsProgressBarWidget" << endl; - m_row.remove_listener(*this); + m_value.remove_progress_listener(*this); } SettingsProgressBarWidget::SettingsProgressBarWidget(QWidget& parent, SettingsResourceProgressBar& value) : QWidget(&parent) , ConfigWidget(value, *this) - // , m_value(value) + , m_value(value) , m_row(value.row) { @@ -352,7 +357,6 @@ SettingsProgressBarWidget::SettingsProgressBarWidget(QWidget& parent, SettingsRe m_progress_bar->setRange(0, 100); m_progress_bar->setValue(0); m_progress_bar->setTextVisible(true); // Shows % inside the bar - m_progress_bar->hide(); // 3. Create a horizontal layout to hold them QHBoxLayout *layout = new QHBoxLayout(); @@ -362,85 +366,47 @@ SettingsProgressBarWidget::SettingsProgressBarWidget(QWidget& parent, SettingsRe this->setLayout(layout); this->setMinimumWidth(170); - m_row.add_listener(*this); -} + value.add_progress_listener(*this); + // m_progress_bar->hide(); + // this->hide(); -void SettingsProgressBarWidget::update_UI_state(){ - ActionState state = m_row.get_action_state(); - switch (state){ - case ActionState::PRE_DOWNLOAD: - case ActionState::DOWNLOADING: - m_status_label->setText("Downloading"); - if (m_progress_bar->isHidden()) { - m_progress_bar->show(); - } - break; - case ActionState::PRE_DELETE: - case ActionState::DELETING: - // m_status_label->setText(""); - // m_progress_bar->hide(); - m_progress_bar->setValue(0); - break; - case ActionState::PRE_CANCEL: - case ActionState::CANCELLING: - // m_status_label->setText(""); - // m_progress_bar->hide(); - m_progress_bar->setValue(0); - break; - case ActionState::READY: - m_status_label->setText(""); - m_progress_bar->hide(); - m_progress_bar->setValue(0); - break; - default: - throw InternalProgramError(nullptr, PA_CURRENT_FUNCTION, "update_UI_state: Unknown enum."); - } + // cout << "progress" << endl; } -void SettingsProgressBarWidget::update_progress_bar(int percentage, const std::string& text){ - if (m_progress_bar->isHidden()) { - m_progress_bar->show(); // Make it visible when progress starts - } - m_status_label->setText(QString::fromStdString(text)); + +void SettingsProgressBarWidget::update_progress_bar(int percentage){ m_progress_bar->setValue(percentage); } -void SettingsProgressBarWidget::update_progress_bar(uint64_t bytes_done, uint64_t total_bytes, const std::string& text){ +void SettingsProgressBarWidget::update_progress_bar(uint64_t bytes_done, uint64_t total_bytes){ double percent = total_bytes > 0 ? (static_cast(bytes_done) / total_bytes) * 100.0 : 0; int current_percent = static_cast(percent); int last_percentage = m_progress_bar->value(); // Only update UI if integer value has changed if (current_percent != last_percentage){ - update_progress_bar(current_percent, text); + update_progress_bar(current_percent); } } -void SettingsProgressBarWidget::on_download_progress(uint64_t bytes_done, uint64_t total_bytes){ - QMetaObject::invokeMethod(this, [this, bytes_done, total_bytes]{ - update_progress_bar(bytes_done, total_bytes, "Downloading"); +void SettingsProgressBarWidget::on_change_text(const std::string& text){ + QMetaObject::invokeMethod(this, [this, text]{ + m_status_label->setText(QString::fromStdString(text)); }, Qt::QueuedConnection); } -void SettingsProgressBarWidget::on_unzip_progress(uint64_t bytes_done, uint64_t total_bytes){ - QMetaObject::invokeMethod(this, [this, bytes_done, total_bytes]{ - update_progress_bar(bytes_done, total_bytes, "Unzipping"); - }, Qt::QueuedConnection); -} -void SettingsProgressBarWidget::on_hash_progress(uint64_t bytes_done, uint64_t total_bytes){ +void SettingsProgressBarWidget::on_update_progress(uint64_t bytes_done, uint64_t total_bytes){ QMetaObject::invokeMethod(this, [this, bytes_done, total_bytes]{ - update_progress_bar(bytes_done, total_bytes, "Verifying"); + update_progress_bar(bytes_done, total_bytes); }, Qt::QueuedConnection); } -// when action_state_updated, update the UI state to match -void SettingsProgressBarWidget::on_action_state_updated(){ + +void SettingsProgressBarWidget::on_reset_progress(){ QMetaObject::invokeMethod(this, [this]{ - update_UI_state(); + m_progress_bar->setValue(0); }, Qt::QueuedConnection); - } - ///////////////////////////////////////////////////////////////////////////////////////////////////////// // SettingsDownloadErrorWidget ///////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.h b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.h index 71ddfca1e7..cb0a7e34d6 100644 --- a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.h +++ b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.h @@ -16,7 +16,7 @@ namespace PokemonAutomation{ -class SettingsDownloadButtonWidget : public QWidget, public ConfigWidget, public SettingsResourceDownloadRow::Listener, SettingsResourceButton::Listener{ +class SettingsDownloadButtonWidget : public QWidget, public ConfigWidget, public SettingsResourceDownloadRow::Listener, public SettingsResourceButton::Listener{ public: using ParentOption = SettingsResourceDownloadButton; @@ -86,7 +86,7 @@ class SettingsCancelButtonWidget : public QWidget, public ConfigWidget, public QPushButton* m_button; }; -class SettingsProgressBarWidget : public QWidget, public ConfigWidget, public SettingsResourceDownloadRow::Listener{ +class SettingsProgressBarWidget : public QWidget, public ConfigWidget, public SettingsResourceProgressBar::Listener{ public: using ParentOption = SettingsResourceProgressBar; @@ -94,19 +94,17 @@ class SettingsProgressBarWidget : public QWidget, public ConfigWidget, public Se ~SettingsProgressBarWidget(); SettingsProgressBarWidget(QWidget& parent, SettingsResourceProgressBar& value); - virtual void on_download_progress(uint64_t bytes_done, uint64_t total_bytes) override; - virtual void on_unzip_progress(uint64_t bytes_done, uint64_t total_bytes) override; - virtual void on_hash_progress(uint64_t bytes_done, uint64_t total_bytes) override; - - virtual void on_action_state_updated() override; +public: // SettingsResourceProgressBar::Listener + virtual void on_change_text(const std::string& text) override; + virtual void on_update_progress(uint64_t bytes_done, uint64_t total_bytes) override; + virtual void on_reset_progress() override; private: - void update_UI_state(); - void update_progress_bar(int percentage, const std::string& text); - void update_progress_bar(uint64_t bytes_done, uint64_t total_bytes, const std::string& text); + void update_progress_bar(int percentage); + void update_progress_bar(uint64_t bytes_done, uint64_t total_bytes); private: - // SettingsResourceProgressBar& m_value; + SettingsResourceProgressBar& m_value; SettingsResourceDownloadRow& m_row; QLabel* m_status_label; QProgressBar* m_progress_bar; From f8acb71d4bc0f7f02a905aa2a77eafca6a5efe80 Mon Sep 17 00:00:00 2001 From: jw098 Date: Sun, 28 Jun 2026 01:22:49 -0700 Subject: [PATCH 05/10] create SettingsDownloadPopup to listen for Row::on_metadata_fetch_finished --- .../SettingsResourceDownloadOptions.cpp | 8 ++ .../SettingsResourceDownloadOptions.h | 7 ++ .../SettingsResourceDownloadRow.cpp | 2 + .../SettingsResourceDownloadRow.h | 1 + .../SettingsResourceDownloadWidget.cpp | 119 ++++++++++-------- .../SettingsResourceDownloadWidget.h | 49 +++++--- 6 files changed, 115 insertions(+), 71 deletions(-) diff --git a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadOptions.cpp b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadOptions.cpp index 3697fcca35..be0bb40ee0 100644 --- a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadOptions.cpp +++ b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadOptions.cpp @@ -120,6 +120,14 @@ void SettingsResourceProgressBar::on_hash_progress(uint64_t bytes_done, uint64_t update_progress(bytes_done, total_bytes); } +////////////////////////////////////// +// SettingsDownloadPopup +////////////////////////////////////// +SettingsDownloadPopup::SettingsDownloadPopup(SettingsResourceDownloadRow& p_row) + : ConfigOptionImpl(LockMode::LOCK_WHILE_RUNNING) + , row(p_row) +{} + ////////////////////////////////////// // SettingsDownloadError ////////////////////////////////////// diff --git a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadOptions.h b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadOptions.h index df85627241..2e265cfc84 100644 --- a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadOptions.h +++ b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadOptions.h @@ -111,6 +111,13 @@ class SettingsResourceProgressBar : public ConfigOptionImpl, public ResourceDownload::Listener{ +public: + SettingsDownloadPopup(SettingsResourceDownloadRow& p_row); +public: + SettingsResourceDownloadRow& row; + +}; class SettingsDownloadError : public ConfigOptionImpl{ public: diff --git a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadRow.cpp b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadRow.cpp index 7893be747c..303368f2fc 100644 --- a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadRow.cpp +++ b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadRow.cpp @@ -153,6 +153,7 @@ SettingsResourceDownloadRow::SettingsResourceDownloadRow( , m_delete_button(*this) , m_cancel_button(*this) , m_progress_bar(*this) + , m_popup(*this) { PA_ADD_STATIC(m_data->m_resource_name_label); PA_ADD_STATIC(m_data->m_file_size_label); @@ -163,6 +164,7 @@ SettingsResourceDownloadRow::SettingsResourceDownloadRow( PA_ADD_STATIC(m_delete_button); PA_ADD_STATIC(m_cancel_button); PA_ADD_STATIC(m_progress_bar); + PA_ADD_STATIC(m_popup); update_action_state(ActionState::READY); } diff --git a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadRow.h b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadRow.h index 4241e813bf..64a0a1ef0a 100644 --- a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadRow.h +++ b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadRow.h @@ -105,6 +105,7 @@ class SettingsResourceDownloadRow : public StaticTableRow, public ResourceDownlo SettingsResourceDeleteButton m_delete_button; SettingsResourceCancelButton m_cancel_button; SettingsResourceProgressBar m_progress_bar; + SettingsDownloadPopup m_popup; LifetimeSanitizer m_lifetime_sanitizer; diff --git a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.cpp b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.cpp index 3e7cb3bebd..a8d4761531 100644 --- a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.cpp +++ b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.cpp @@ -27,7 +27,6 @@ template class RegisterConfigWidget; SettingsDownloadButtonWidget::~SettingsDownloadButtonWidget(){ // cout << "Destructor for SettingsDownloadButtonWidget" << endl; // m_value.disconnect(this); - m_row.remove_listener(*this); m_value.remove_button_listener(*this); } SettingsDownloadButtonWidget::SettingsDownloadButtonWidget(QWidget& parent, SettingsResourceDownloadButton& value) @@ -71,7 +70,6 @@ SettingsDownloadButtonWidget::SettingsDownloadButtonWidget(QWidget& parent, Sett ); - m_row.add_listener(*this); value.add_button_listener(*this); } @@ -83,54 +81,6 @@ void SettingsDownloadButtonWidget::on_change_text(const std::string& text){ } -void SettingsDownloadButtonWidget::show_download_confirm_box( - const std::string& title, - const std::string& message_body -){ - QMessageBox box; - QPushButton* ok = box.addButton(QMessageBox::Ok); - QPushButton* cancel = box.addButton("Cancel", QMessageBox::NoRole); - box.setEscapeButton(cancel); -// cout << "ok = " << ok << endl; -// cout << "skip = " << skip << endl; - - box.setTextFormat(Qt::RichText); - std::string text = message_body; - // text += make_text_url(link_url, link_text); - // text += get_changes(node); - - - box.setWindowTitle(QString::fromStdString(title)); - box.setText(QString::fromStdString(text)); - -// box.open(); - - box.exec(); - - QAbstractButton* clicked = box.clickedButton(); -// cout << "clicked = " << clicked << endl; - if (clicked == ok){ - cout << "Clicked Ok to Download" << endl; - - m_row.start_download(); - return; - } - if (clicked == cancel){ - m_row.update_action_state(ActionState::READY); - return; - } -} - -// when json has been fetched, open the update box. -// When click Ok in update box, start the download. If click cancel, re-enable the download button -void SettingsDownloadButtonWidget::on_metadata_fetch_finished(const std::string& popup_message){ - QMetaObject::invokeMethod(this, [this, popup_message]{ - show_download_confirm_box("Download", popup_message); - }, Qt::QueuedConnection); - -} - - ///////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -139,7 +89,6 @@ void SettingsDownloadButtonWidget::on_metadata_fetch_finished(const std::string& template class RegisterConfigWidget; SettingsDeleteButtonWidget::~SettingsDeleteButtonWidget(){ - m_row.remove_listener(*this); m_value.remove_button_listener(*this); } SettingsDeleteButtonWidget::SettingsDeleteButtonWidget(QWidget& parent, SettingsResourceDeleteButton& value) @@ -181,7 +130,6 @@ SettingsDeleteButtonWidget::SettingsDeleteButtonWidget(QWidget& parent, Settings } ); - m_row.add_listener(*this); value.add_button_listener(*this); } @@ -232,7 +180,6 @@ void SettingsDeleteButtonWidget::show_delete_confirm_box(){ template class RegisterConfigWidget; SettingsCancelButtonWidget::~SettingsCancelButtonWidget(){ - m_row.remove_listener(*this); m_value.remove_button_listener(*this); } SettingsCancelButtonWidget::SettingsCancelButtonWidget(QWidget& parent, SettingsResourceCancelButton& value) @@ -273,7 +220,6 @@ SettingsCancelButtonWidget::SettingsCancelButtonWidget(QWidget& parent, Settings } ); - m_row.add_listener(*this); value.add_button_listener(*this); } @@ -368,6 +314,8 @@ SettingsProgressBarWidget::SettingsProgressBarWidget(QWidget& parent, SettingsRe value.add_progress_listener(*this); + // value.set_visibility(ConfigOptionState::HIDDEN); + // m_progress_bar->hide(); // this->hide(); @@ -407,6 +355,69 @@ void SettingsProgressBarWidget::on_reset_progress(){ }, Qt::QueuedConnection); } +///////////////////////////////////////////////////////////////////////////////////////////////////////// +// SettingsDownloadPopupWidget +///////////////////////////////////////////////////////////////////////////////////////////////////////// +template class RegisterConfigWidget; +SettingsDownloadPopupWidget::~SettingsDownloadPopupWidget(){ + m_row.remove_listener(*this); +} +SettingsDownloadPopupWidget::SettingsDownloadPopupWidget(QWidget& parent, SettingsDownloadPopup& value) + : QWidget(&parent) + , ConfigWidget(value, *this) + , m_value(value) + , m_row(value.row) +{ + m_row.add_listener(*this); +} + +void SettingsDownloadPopupWidget::show_download_confirm_box( + const std::string& title, + const std::string& message_body +){ + QMessageBox box; + QPushButton* ok = box.addButton(QMessageBox::Ok); + QPushButton* cancel = box.addButton("Cancel", QMessageBox::NoRole); + box.setEscapeButton(cancel); +// cout << "ok = " << ok << endl; +// cout << "skip = " << skip << endl; + + box.setTextFormat(Qt::RichText); + std::string text = message_body; + // text += make_text_url(link_url, link_text); + // text += get_changes(node); + + + box.setWindowTitle(QString::fromStdString(title)); + box.setText(QString::fromStdString(text)); + +// box.open(); + + box.exec(); + + QAbstractButton* clicked = box.clickedButton(); +// cout << "clicked = " << clicked << endl; + if (clicked == ok){ + cout << "Clicked Ok to Download" << endl; + + m_row.start_download(); + return; + } + if (clicked == cancel){ + m_row.update_action_state(ActionState::READY); + return; + } +} + +// when json has been fetched, open the update box. +// When click Ok in update box, start the download. If click cancel, re-enable the download button +void SettingsDownloadPopupWidget::on_metadata_fetch_finished(const std::string& popup_message){ + QMetaObject::invokeMethod(this, [this, popup_message]{ + show_download_confirm_box("Download", popup_message); + }, Qt::QueuedConnection); + +} + ///////////////////////////////////////////////////////////////////////////////////////////////////////// // SettingsDownloadErrorWidget ///////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.h b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.h index cb0a7e34d6..7da4116391 100644 --- a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.h +++ b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.h @@ -16,7 +16,7 @@ namespace PokemonAutomation{ -class SettingsDownloadButtonWidget : public QWidget, public ConfigWidget, public SettingsResourceDownloadRow::Listener, public SettingsResourceButton::Listener{ +class SettingsDownloadButtonWidget : public QWidget, public ConfigWidget, public SettingsResourceButton::Listener{ public: using ParentOption = SettingsResourceDownloadButton; @@ -24,17 +24,10 @@ class SettingsDownloadButtonWidget : public QWidget, public ConfigWidget, public ~SettingsDownloadButtonWidget(); SettingsDownloadButtonWidget(QWidget& parent, SettingsResourceDownloadButton& value); -public: // SettingsResourceDownloadRow::Listener - virtual void on_metadata_fetch_finished(const std::string& popup_message) override; public: // SettingsResourceButton::Listener virtual void on_change_text(const std::string& text) override; -private: - void show_download_confirm_box( - const std::string& title, - const std::string& message_body - ); private: SettingsResourceDownloadButton& m_value; @@ -44,7 +37,7 @@ class SettingsDownloadButtonWidget : public QWidget, public ConfigWidget, public }; -class SettingsDeleteButtonWidget : public QWidget, public ConfigWidget, public SettingsResourceDownloadRow::Listener, SettingsResourceButton::Listener{ +class SettingsDeleteButtonWidget : public QWidget, public ConfigWidget, SettingsResourceButton::Listener{ public: using ParentOption = SettingsResourceDeleteButton; @@ -53,19 +46,19 @@ class SettingsDeleteButtonWidget : public QWidget, public ConfigWidget, public SettingsDeleteButtonWidget(QWidget& parent, SettingsResourceDeleteButton& value); -private: // SettingsResourceDownloadRow::Listener - void show_delete_confirm_box(); - public: // SettingsResourceButton::Listener virtual void on_change_text(const std::string& text) override; +private: + void show_delete_confirm_box(); + private: SettingsResourceDeleteButton& m_value; SettingsResourceDownloadRow& m_row; QPushButton* m_button; }; -class SettingsCancelButtonWidget : public QWidget, public ConfigWidget, public SettingsResourceDownloadRow::Listener, SettingsResourceButton::Listener{ +class SettingsCancelButtonWidget : public QWidget, public ConfigWidget, SettingsResourceButton::Listener{ public: using ParentOption = SettingsResourceCancelButton; @@ -73,13 +66,12 @@ class SettingsCancelButtonWidget : public QWidget, public ConfigWidget, public ~SettingsCancelButtonWidget(); SettingsCancelButtonWidget(QWidget& parent, SettingsResourceCancelButton& value); - -private: // SettingsResourceDownloadRow::Listener - void show_cancel_confirm_box(); - public: // SettingsResourceButton::Listener virtual void on_change_text(const std::string& text) override; +private: + void show_cancel_confirm_box(); + private: SettingsResourceCancelButton& m_value; SettingsResourceDownloadRow& m_row; @@ -110,6 +102,29 @@ class SettingsProgressBarWidget : public QWidget, public ConfigWidget, public Se QProgressBar* m_progress_bar; }; + +class SettingsDownloadPopupWidget : public QWidget, public ConfigWidget, public SettingsResourceDownloadRow::Listener{ +public: + using ParentOption = SettingsDownloadPopup; + +public: + ~SettingsDownloadPopupWidget(); + SettingsDownloadPopupWidget(QWidget& parent, SettingsDownloadPopup& value); + +public: // SettingsResourceDownloadRow::Listener + virtual void on_metadata_fetch_finished(const std::string& popup_message) override; + +private: + void show_download_confirm_box( + const std::string& title, + const std::string& message_body + ); + +private: + SettingsDownloadPopup& m_value; + SettingsResourceDownloadRow& m_row; + +}; class SettingsDownloadErrorWidget : public QWidget, public ConfigWidget, public GlobalResourceDownloadManager::Listener{ public: using ParentOption = SettingsDownloadError; From f0de820c137af59686fa45f2824d201cf183a245 Mon Sep 17 00:00:00 2001 From: jw098 Date: Sun, 28 Jun 2026 01:44:59 -0700 Subject: [PATCH 06/10] fix build --- .../ResourceDownload/SettingsResourceDownloadWidget.cpp | 4 ++-- .../ResourceDownload/SettingsResourceDownloadWidget.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.cpp b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.cpp index a8d4761531..eb02eeefbc 100644 --- a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.cpp +++ b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.cpp @@ -290,7 +290,7 @@ SettingsProgressBarWidget::SettingsProgressBarWidget(QWidget& parent, SettingsRe : QWidget(&parent) , ConfigWidget(value, *this) , m_value(value) - , m_row(value.row) + // , m_row(value.row) { // 1. Instantiate the widgets @@ -365,7 +365,7 @@ SettingsDownloadPopupWidget::~SettingsDownloadPopupWidget(){ SettingsDownloadPopupWidget::SettingsDownloadPopupWidget(QWidget& parent, SettingsDownloadPopup& value) : QWidget(&parent) , ConfigWidget(value, *this) - , m_value(value) + // , m_value(value) , m_row(value.row) { m_row.add_listener(*this); diff --git a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.h b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.h index 7da4116391..c78beb738b 100644 --- a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.h +++ b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.h @@ -97,7 +97,7 @@ class SettingsProgressBarWidget : public QWidget, public ConfigWidget, public Se private: SettingsResourceProgressBar& m_value; - SettingsResourceDownloadRow& m_row; + // SettingsResourceDownloadRow& m_row; QLabel* m_status_label; QProgressBar* m_progress_bar; }; @@ -121,7 +121,7 @@ class SettingsDownloadPopupWidget : public QWidget, public ConfigWidget, public ); private: - SettingsDownloadPopup& m_value; + // SettingsDownloadPopup& m_value; SettingsResourceDownloadRow& m_row; }; From 538712c8398b933f885f5989676b79d422fc4773 Mon Sep 17 00:00:00 2001 From: jw098 Date: Sun, 5 Jul 2026 16:10:13 -0700 Subject: [PATCH 07/10] fix update_visibility() so that it hides the ProgressBar --- .../SettingsResourceDownloadWidget.cpp | 18 ++++++++++++++---- .../SettingsResourceDownloadWidget.h | 4 ++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.cpp b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.cpp index eb02eeefbc..4c298b4f82 100644 --- a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.cpp +++ b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.cpp @@ -314,12 +314,22 @@ SettingsProgressBarWidget::SettingsProgressBarWidget(QWidget& parent, SettingsRe value.add_progress_listener(*this); - // value.set_visibility(ConfigOptionState::HIDDEN); + update_visibility(); +} - // m_progress_bar->hide(); - // this->hide(); +void SettingsProgressBarWidget::update_visibility(){ + ConfigWidget::update_visibility(); + + switch (m_value.visibility()){ + case ConfigOptionState::ENABLED: + case ConfigOptionState::DISABLED: + m_progress_bar->setVisible(true); + break; + case ConfigOptionState::HIDDEN: + m_progress_bar->setVisible(false); + break; + } - // cout << "progress" << endl; } diff --git a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.h b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.h index c78beb738b..0bf877fd3f 100644 --- a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.h +++ b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadWidget.h @@ -86,6 +86,10 @@ class SettingsProgressBarWidget : public QWidget, public ConfigWidget, public Se ~SettingsProgressBarWidget(); SettingsProgressBarWidget(QWidget& parent, SettingsResourceProgressBar& value); + // Because this widget is within a table, QT doesn't respect setVisible + // so we need to override update_visibility and manually hide/show the progress_bar. + virtual void update_visibility() override; + public: // SettingsResourceProgressBar::Listener virtual void on_change_text(const std::string& text) override; virtual void on_update_progress(uint64_t bytes_done, uint64_t total_bytes) override; From 0661989233583f55f79a8c67fa7698e8c558d8ba Mon Sep 17 00:00:00 2001 From: jw098 Date: Tue, 7 Jul 2026 12:17:35 -0700 Subject: [PATCH 08/10] use ScopeExit to always update action state. --- .../SettingsResourceDownloadRow.cpp | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadRow.cpp b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadRow.cpp index 303368f2fc..5bd49776a3 100644 --- a/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadRow.cpp +++ b/SerialPrograms/Source/CommonFramework/ResourceDownload/SettingsResourceDownloadRow.cpp @@ -10,6 +10,7 @@ #include "Common/Cpp/ListenerSet.h" #include "Common/Cpp/Concurrency/AsyncTask.h" #include "Common/Cpp/Filesystem.h" +#include "Common/Cpp/ScopeExit.h" #include "CommonFramework/Options/LabelCellOption.h" #include "CommonFramework/Tools/GlobalThreadPools.h" #include "CommonFramework/Exceptions/OperationFailedException.h" @@ -212,6 +213,14 @@ void SettingsResourceDownloadRow::ensure_remote_metadata_loaded(){ if (!is_given_action_state(ActionState::PRE_DOWNLOAD)){ return; } + + + bool success = false; + ScopeExit on_exit([&success, this]{ + if (!success){ + update_action_state(ActionState::READY); + } + }); // std::this_thread::sleep_for(std::chrono::seconds(1)); std::string predownload_warning; @@ -226,18 +235,14 @@ void SettingsResourceDownloadRow::ensure_remote_metadata_loaded(){ // Logger& logger = global_logger_tagged(); // throw_and_log(logger, ErrorReport::NO_ERROR_REPORT, "test"); - // update_action_state(ActionState::READY); report_metadata_fetch_finished(predownload_warning); + success = true; }catch(OperationFailedException&){ // cout << "failed" << endl; - // update_table_label(false); - update_action_state(ActionState::READY); GlobalResourceDownloadManager::instance().report_download_failed(m_data->m_resource_slug); return; }catch(...){ - // update_table_label(false); - update_action_state(ActionState::READY); // cout << "Exception thrown in thread" << endl; GlobalResourceDownloadManager::instance().report_unexpected_exception_caught("Error: SettingsResourceDownloadButton::ensure_remote_metadata_loaded: Unknown exception. Report this as an error."); return; @@ -301,6 +306,10 @@ void SettingsResourceDownloadRow::start_delete(){ m_data->m_delete_thread = GlobalThreadPools::unlimited_normal().dispatch_now_blocking( [this]{ try { + ScopeExit on_exit([this]{ + update_table_label(false); + update_action_state(ActionState::READY); + }); // throw InternalProgramError(nullptr, PA_CURRENT_FUNCTION, "test."); // Logger& logger = global_logger_tagged(); @@ -317,19 +326,12 @@ void SettingsResourceDownloadRow::start_delete(){ // delete directory and the old resource fs::remove_all(Filesystem::Path(resource_directory)); - // update the table labels - set_is_downloaded(false); - set_version_status(ResourceVersionStatus::NOT_APPLICABLE); - - update_action_state(ActionState::READY); }catch(OperationFailedException& e){ std::cerr << e.message() << endl; - update_action_state(ActionState::READY); GlobalResourceDownloadManager::instance().report_unexpected_exception_caught( "Error: SettingsResourceDownloadButton::start_delete: Unexpected OperationFailedException exception. Report this as an error."); return; }catch(...){ - update_action_state(ActionState::READY); GlobalResourceDownloadManager::instance().report_unexpected_exception_caught( "Error: SettingsResourceDownloadButton::start_delete: Unknown exception. Report this as an error."); return; From faa005bdc61340416d3607deb0b2f93ca546bdc4 Mon Sep 17 00:00:00 2001 From: jw098 Date: Tue, 7 Jul 2026 12:44:28 -0700 Subject: [PATCH 09/10] gate resource downloading behind dev mode --- .../Source/CommonFramework/GlobalSettingsPanel.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/SerialPrograms/Source/CommonFramework/GlobalSettingsPanel.cpp b/SerialPrograms/Source/CommonFramework/GlobalSettingsPanel.cpp index e3ff40a6ca..7adcbb9497 100644 --- a/SerialPrograms/Source/CommonFramework/GlobalSettingsPanel.cpp +++ b/SerialPrograms/Source/CommonFramework/GlobalSettingsPanel.cpp @@ -266,10 +266,13 @@ GlobalSettings::GlobalSettings() PA_ADD_OPTION(STATS_FILE); PA_ADD_OPTION(TEMP_FOLDER); PA_ADD_OPTION(THEME); - PA_ADD_OPTION(USE_PADDLE_OCR); PA_ADD_OPTION(USE_GPU_FOR_ML_INFERENCE); + + // gated behind Dev mode. see GlobalSettings::load_json + PA_ADD_OPTION(USE_PADDLE_OCR); PA_ADD_OPTION(RESOURCE_DOWNLOAD_TABLE); PA_ADD_OPTION(DOWNLOAD_ERROR); + PA_ADD_OPTION(WINDOW_SIZE); PA_ADD_OPTION(LOG_WINDOW_SIZE); PA_ADD_OPTION(LOG_WINDOW_STARTUP); @@ -291,6 +294,8 @@ GlobalSettings::GlobalSettings() PA_ADD_STATIC(m_advanced_options); PA_ADD_OPTION(LOG_EVERYTHING); PA_ADD_OPTION(SAVE_DEBUG_IMAGES); + + // gated behind Dev mode. see GlobalSettings::load_json PA_ADD_OPTION(SAVE_DEBUG_VIDEOS_ON_SWITCH); // PA_ADD_OPTION(NAUGHTY_MODE); // PA_ADD_OPTION(HIDE_NOTIF_DISCORD_LINK); @@ -300,6 +305,8 @@ GlobalSettings::GlobalSettings() PA_ADD_OPTION(AUDIO_PIPELINE); PA_ADD_OPTION(VIDEO_PIPELINE); PA_ADD_OPTION(COMMAND_QUEUE_LIMIT); + + // gated behind Dev mode. see GlobalSettings::load_json PA_ADD_OPTION(DEVICE_LOGGING_FLAG); PA_ADD_OPTION(ENABLE_LIFETIME_SANITIZER0); @@ -329,6 +336,8 @@ void GlobalSettings::load_json(const JsonValue& json){ ? ConfigOptionState::ENABLED : ConfigOptionState::HIDDEN; USE_PADDLE_OCR.set_visibility(devmode_visibility); + RESOURCE_DOWNLOAD_TABLE.set_visibility(devmode_visibility); + DOWNLOAD_ERROR.set_visibility(devmode_visibility); SAVE_DEBUG_VIDEOS_ON_SWITCH.set_visibility(devmode_visibility); DEVICE_LOGGING_FLAG.set_visibility(devmode_visibility); From 3830d54f797504a934f69543a7b36f6650bc9554 Mon Sep 17 00:00:00 2001 From: jw098 Date: Tue, 7 Jul 2026 13:18:16 -0700 Subject: [PATCH 10/10] update URL --- .../ResourceDownload/ResourceDownloadHelpers.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SerialPrograms/Source/CommonFramework/ResourceDownload/ResourceDownloadHelpers.cpp b/SerialPrograms/Source/CommonFramework/ResourceDownload/ResourceDownloadHelpers.cpp index 198d75d34e..399bd4c40a 100644 --- a/SerialPrograms/Source/CommonFramework/ResourceDownload/ResourceDownloadHelpers.cpp +++ b/SerialPrograms/Source/CommonFramework/ResourceDownload/ResourceDownloadHelpers.cpp @@ -79,7 +79,7 @@ JsonValue fetch_resource_download_list_json_from_remote(){ JsonValue json = FileDownloader::download_json_file( logger, - "https://raw.githubusercontent.com/jw098/Packages/refs/heads/download/Resources/ResourceDownloadList.json" + "https://raw.githubusercontent.com/PokemonAutomation/Packages/refs/heads/master/Resources/ResourceDownloadList.json" ); return json;