Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
b2a70db
add resource downloading table - minimal implementation
jw098 Mar 15, 2026
7a51707
move ResourceDownloadTable.h to ResourceDownload folder
jw098 Mar 15, 2026
306eb13
add DownloadButton and DownloadButtonWidget
jw098 Mar 15, 2026
8378b7f
add Delete Button
jw098 Mar 15, 2026
64a5534
add_rows_from_resource_list_json
jw098 Mar 16, 2026
ed2a976
refactor so that we keep a handle on m_resources and m_resource_rows.
jw098 Mar 16, 2026
b98f2aa
check if resource is downloaded
jw098 Mar 17, 2026
d9cab91
check if downloaded. add "Version" column
jw098 Mar 17, 2026
56dcfd2
add DOWNLOADED_RESOURCE_PATH()
jw098 Mar 17, 2026
b18a9a9
initial implementation of updating "Version" column on a separate thr…
jw098 Mar 17, 2026
0515831
initialize worker thread outside of constructor
jw098 Mar 18, 2026
b03ca41
convert member fields to PIMPL
jw098 Mar 18, 2026
4541a37
add version number to the JSON
jw098 Mar 19, 2026
db182f8
update version_num, version_status for each row
jw098 Mar 19, 2026
6e0bc14
refactor Row class into its own file
jw098 Mar 20, 2026
5388ba5
clicking Download button disables it until action is done
jw098 Mar 20, 2026
fc76cda
add download pop-up
jw098 Mar 21, 2026
be7ee03
move functions to Helper class to avoid circular dependency. lazy ini…
jw098 Mar 24, 2026
4b17f7d
cleanup headers
jw098 Mar 24, 2026
ac2bc39
print to console when throwing ParseException
jw098 Mar 25, 2026
ee33049
update exception handling within the thread. add predownload_warning_…
jw098 Mar 25, 2026
a520d75
FileDownloader::download_file_to_disk
jw098 Mar 26, 2026
eb4af18
initial progress bar implementation
jw098 Mar 26, 2026
c78d4d3
fix Download button
jw098 Mar 27, 2026
2d5c948
added static progress bar to UI
jw098 Mar 27, 2026
654f15f
refactor. move functions out of DownloadButton into Row. Move buttons…
jw098 Mar 27, 2026
a0a70d2
more refactor of ResourceDownloadRow class. pass local_metadata to it…
jw098 Mar 27, 2026
5f03bb3
working implementation of Progress bar. fix inheritance for DownloadW…
jw098 Mar 27, 2026
0c2bfc5
download failed pop-up if internet disconnected.
jw098 Mar 27, 2026
5a771d2
delete folder prior to downloading. create parent directory during th…
jw098 Mar 31, 2026
38b9792
catch errors with get_resource_version_num()
jw098 Mar 31, 2026
746eff7
add unzip progress bar
jw098 Mar 31, 2026
03689ac
minor UI changes with the progress bar
jw098 Mar 31, 2026
f777903
minor fix
jw098 Mar 31, 2026
7d125a8
update the Version and Downloaded column after downloading
jw098 Apr 1, 2026
4874eef
add cancel button
jw098 Apr 1, 2026
abcd6e8
add cancel callback to download routine
jw098 Apr 1, 2026
90e43b2
add cancel callback to unzip function
jw098 Apr 2, 2026
078786a
refactor: move logic from DownloadButton class to DownloadRow class.
jw098 Apr 2, 2026
c621b09
implement delete action for Delete button
jw098 Apr 2, 2026
7ae6c90
unzip routine will throw OperationCancelledException if cancelled. an…
jw098 Apr 3, 2026
cb28e41
adjust logic that updates button state
jw098 Apr 3, 2026
8484ba2
update UI state for progress bar
jw098 Apr 4, 2026
53daba0
adjust text and width of buttons
jw098 Apr 4, 2026
d4ae873
get SHA 256 after each download
jw098 Apr 8, 2026
7ea35b3
compare with expected hash
jw098 Apr 8, 2026
15cb29e
minior UI changes. update file size in table to KiB/MiB/GiB.
jw098 Apr 8, 2026
36dfc7d
minor changes
jw098 Apr 8, 2026
334935f
remove tabs
jw098 Apr 8, 2026
15b69d8
fix build
jw098 Apr 8, 2026
cf7a3d2
fix build
jw098 Apr 9, 2026
5824c48
use Filesystem::Path instead of implicitly using std::filesystem
jw098 Apr 9, 2026
7f03141
fix build
jw098 Apr 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Common/Cpp/Exceptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ std::string Exception::to_str() const{
}


ParseException::ParseException(std::string message_string)
: m_message(std::move(message_string))
{
std::string str = ParseException::name();
str += ": " + message();
std::cerr << str << std::endl;
}



FileException::FileException(Logger* logger, const char* location, std::string message_string, std::string file)
Expand Down
2 changes: 1 addition & 1 deletion Common/Cpp/Exceptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ class OperationCancelledException : public Exception{
class ParseException : public Exception{
public:
ParseException() = default;
ParseException(std::string message) : m_message(std::move(message)) {}
ParseException(std::string message);
virtual const char* name() const override{ return "ParseException"; }
virtual std::string message() const override{ return m_message; }
protected:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ GlobalSettings::GlobalSettings()
PA_ADD_OPTION(TEMP_FOLDER);
PA_ADD_OPTION(THEME);
PA_ADD_OPTION(USE_PADDLE_OCR);
PA_ADD_OPTION(RESOURCE_DOWNLOAD_TABLE);
PA_ADD_OPTION(WINDOW_SIZE);
PA_ADD_OPTION(LOG_WINDOW_SIZE);
PA_ADD_OPTION(LOG_WINDOW_STARTUP);
Expand Down
2 changes: 2 additions & 0 deletions SerialPrograms/Source/CommonFramework/GlobalSettingsPanel.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "Common/Cpp/Options/StringOption.h"
#include "CommonFramework/Panels/SettingsPanel.h"
#include "CommonFramework/Panels/PanelTools.h"
#include "CommonFramework/ResourceDownload/ResourceDownloadTable.h"

//#include <iostream>
//using std::cout;
Expand Down Expand Up @@ -124,6 +125,7 @@ class GlobalSettings : public BatchOption, private ConfigOption::Listener, priva

Pimpl<ThemeSelectorOption> THEME;
BooleanCheckBoxOption USE_PADDLE_OCR;
ResourceDownloadTable RESOURCE_DOWNLOAD_TABLE;
Pimpl<ResolutionOption> WINDOW_SIZE;
Pimpl<ResolutionOption> LOG_WINDOW_SIZE;
BooleanCheckBoxOption LOG_WINDOW_STARTUP;
Expand Down
4 changes: 4 additions & 0 deletions SerialPrograms/Source/CommonFramework/Globals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,10 @@ const std::string& RESOURCE_PATH(){
static std::string path = get_resource_path();
return path;
}
const std::string& DOWNLOADED_RESOURCE_PATH(){
static std::string path = RUNTIME_BASE_PATH() + "DownloadedResources/";
return path;
}
const std::string& TRAINING_PATH(){
static std::string path = get_training_path();
return path;
Expand Down
4 changes: 4 additions & 0 deletions SerialPrograms/Source/CommonFramework/Globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ const std::string& USER_FILE_PATH();
// Resource folder path. Resources include JSON files, images, sound files and others required by
// various automation programs.
const std::string& RESOURCE_PATH();

// Folder path that holds Downloaded resources
const std::string& DOWNLOADED_RESOURCE_PATH();

// Hold ML training data.
const std::string& TRAINING_PATH();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include "Common/Cpp/Containers/Pimpl.tpp"
#include "Common/Cpp/Json/JsonValue.h"
#include "Common/Cpp/Concurrency/SpinLock.h"
#include "LabelCellOption.h"

//#include <iostream>
Expand All @@ -17,7 +18,7 @@ namespace PokemonAutomation{


struct LabelCellOption::Data{
// mutable SpinLock m_lock;
mutable SpinLock m_lock;
std::string m_text;
// ImageRGB32 m_icon_owner;
ImageViewRGB32 m_icon;
Expand Down Expand Up @@ -80,6 +81,7 @@ LabelCellOption::LabelCellOption(
// : m_data(CONSTRUCT_TOKEN, std::move(text), std::move(icon))
//{}
const std::string& LabelCellOption::text() const{
ReadSpinLock lg(m_data->m_lock);
return m_data->m_text;
}
const ImageViewRGB32& LabelCellOption::icon() const{
Expand All @@ -94,6 +96,18 @@ JsonValue LabelCellOption::to_json() const{
return JsonValue();
}

void LabelCellOption::set_text(std::string x){
// sanitize(x);
{
WriteSpinLock lg(m_data->m_lock);
if (m_data->m_text == x){
return;
}
m_data->m_text = std::move(x);
}
report_value_changed(this);
}




Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ class LabelCellOption : public ConfigOptionImpl<LabelCellOption>{
const ImageViewRGB32& icon() const;
Resolution resolution() const;

void set_text(std::string x);

virtual void load_json(const JsonValue& json) override;
virtual JsonValue to_json() const override;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ LabelCellWidget::~LabelCellWidget(){
LabelCellWidget::LabelCellWidget(QWidget& parent, LabelCellOption& value)
: QWidget(&parent)
, ConfigWidget(value, *this)
// , m_value(value)
, m_value(value)
{
QHBoxLayout* layout = new QHBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
Expand All @@ -49,6 +49,17 @@ LabelCellWidget::LabelCellWidget(QWidget& parent, LabelCellOption& value)
layout->addWidget(m_text, 1);
// text->setTextInteractionFlags(Qt::TextBrowserInteraction);
// m_text->setOpenExternalLinks(true);

m_value.add_listener(*this);
}

void LabelCellWidget::update_value(){
m_text->setText(QString::fromStdString(m_value.text()));
}
void LabelCellWidget::on_config_value_changed(void* object){
QMetaObject::invokeMethod(m_text, [this]{
update_value();
}, Qt::QueuedConnection);
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,11 @@ class LabelCellWidget : public QWidget, public ConfigWidget{
~LabelCellWidget();
LabelCellWidget(QWidget& parent, LabelCellOption& value);

virtual void update_value() override;
virtual void on_config_value_changed(void* object) override;

private:
// LabelCellOption& m_value;
LabelCellOption& m_value;
QLabel* m_icon = nullptr;
QLabel* m_text;
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
/* Resource Download Helpers
*
* From: https://github.com/PokemonAutomation/
*
*/

#include "CommonFramework/Globals.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 "ResourceDownloadHelpers.h"

// #include <filesystem>
// #include <thread>
// #include <unordered_set>

#include <iostream>
using std::cout;
using std::endl;

namespace PokemonAutomation{


ResourceType get_resource_type_from_string(std::string type){
if (type == "ZippedFolder"){
return ResourceType::ZIP_FILE;
}else{
throw InternalProgramError(nullptr, PA_CURRENT_FUNCTION, "get_resource_type_from_string: Unknown string.");
}

}

std::vector<DownloadedResourceMetadata> deserialize_resource_list_json(const JsonValue& json){
std::vector<DownloadedResourceMetadata> resources;

try{
const JsonObject& obj = json.to_object_throw();
const JsonArray& resource_list = obj.get_array_throw("resourceList");
for (const JsonValue& resource_val : resource_list){
const JsonObject& resource_obj = resource_val.to_object_throw();

std::string resource_name = resource_obj.get_string_throw("resourceName");
std::optional<uint16_t> version_num = (uint16_t)resource_obj.get_integer_throw("version");
ResourceType resource_type = get_resource_type_from_string(resource_obj.get_string_throw("Type"));
size_t compressed_bytes = (size_t)resource_obj.get_integer_throw("CompressedBytes");
size_t decompressed_bytes = (size_t)resource_obj.get_integer_throw("DecompressedBytes");
std::string url = resource_obj.get_string_throw("URL");
std::string sha_256 = resource_obj.get_string_throw("SHA_256");

DownloadedResourceMetadata resource = {
resource_name,
version_num,
resource_type,
compressed_bytes,
decompressed_bytes,
url,
sha_256
};

resources.emplace_back(std::move(resource));

}

}catch (ParseException&){
std::cerr << "JSON parsing error. Given JSON file doesn't match the expected format." << endl;
// throw ParseException("JSON parsing error. Given JSON file doesn't match the expected format.");
return std::vector<DownloadedResourceMetadata>();
}

return resources;
}


const std::vector<DownloadedResourceMetadata>& local_resource_download_list(){
// cout << "local_resource_download_list" << endl;
static std::vector<DownloadedResourceMetadata> local_resources = deserialize_resource_list_json(load_json_file(RESOURCE_PATH() + "ResourceDownloadList.json"));

return local_resources;
}


JsonValue fetch_resource_download_list_json_from_remote(){
Logger& logger = global_logger_tagged();
JsonValue json =
FileDownloader::download_json_file(
logger,
"https://raw.githubusercontent.com/jw098/Packages/refs/heads/download/Resources/ResourceDownloadList.json"
);

return json;
}

const JsonValue& remote_resource_download_list_json(){
static const JsonValue json = fetch_resource_download_list_json_from_remote();

return json;
}

const std::vector<DownloadedResourceMetadata>& remote_resource_download_list(){
// cout << "remote_resource_download_list" << endl;
static std::vector<DownloadedResourceMetadata> remote_resources = deserialize_resource_list_json(remote_resource_download_list_json());

return remote_resources;
}

std::optional<uint16_t> get_resource_version_num(Filesystem::Path folder_path){
try{
std::string file_name = folder_path.string() + "/version.json";
const JsonValue& json = load_json_file(file_name);

const JsonObject& obj = json.to_object_throw();
uint16_t version_num = (uint16_t)obj.get_integer_throw("version");
return version_num;
}catch(...){
std::cerr << "Unable to determine the version number from version.json." << endl;
return std::nullopt;
}

}

ResourceVersionStatus get_version_status(uint16_t expected_version_num, std::optional<uint16_t> current_version_num){
if (!current_version_num.has_value()){
return ResourceVersionStatus::NOT_APPLICABLE;
}

if (current_version_num < expected_version_num){
return ResourceVersionStatus::OUTDATED;
}else if (current_version_num == expected_version_num){
return ResourceVersionStatus::CURRENT;
}else{ // current > expected
return ResourceVersionStatus::FUTURE_VERSION;
}
}



}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/* Resource Download Helpers
*
* From: https://github.com/PokemonAutomation/
*
*/

#ifndef PokemonAutomation_ResourceDownloadHelpers_H
#define PokemonAutomation_ResourceDownloadHelpers_H

#include <string>
#include <optional>


namespace PokemonAutomation{

namespace Filesystem{
class Path;
}


enum class ResourceType{
ZIP_FILE,
};

struct DownloadedResourceMetadata{
std::string resource_name;
std::optional<uint16_t> version_num;
ResourceType resource_type;
size_t size_compressed_bytes;
size_t size_decompressed_bytes;
std::string url;
std::string sha_256;
};

enum class ResourceVersionStatus{
CURRENT,
OUTDATED, // still used, but newer version available
FUTURE_VERSION, // current version number is greater than the expected version number
NOT_APPLICABLE, // resource not downloaded locally, so can't get its version
// RETIRED, // no longer used
// BLANK, // not yet fetched version info from remote
};

enum class RemoteMetadataStatus{
UNINITIALIZED,
NOT_AVAILABLE,
AVAILABLE,
};
struct RemoteMetadata {
RemoteMetadataStatus status = RemoteMetadataStatus::UNINITIALIZED;
DownloadedResourceMetadata metadata;
};


const std::vector<DownloadedResourceMetadata>& local_resource_download_list();
const std::vector<DownloadedResourceMetadata>& remote_resource_download_list();
std::optional<uint16_t> get_resource_version_num(Filesystem::Path folder_path);
ResourceVersionStatus get_version_status(uint16_t expected_version_num, std::optional<uint16_t> current_version_num);

}
#endif
Loading