Move cloud transfer helpers to legacy cloud services
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -82,6 +82,12 @@ The cloud browser dialog now also opens through that seam from
|
|||||||
now concentrated in retained background worker threads, transfer helpers,
|
now concentrated in retained background worker threads, transfer helpers,
|
||||||
project-open refresh, and dialog-internal legacy behavior instead of raw root
|
project-open refresh, and dialog-internal legacy behavior instead of raw root
|
||||||
insertion.
|
insertion.
|
||||||
|
Retained upload/download CURL setup, TLS-bypass policy consumption, and
|
||||||
|
progress callback dispatch now also live in `src/legacy_cloud_services.*`
|
||||||
|
instead of `App::upload` and `App::download`, leaving the remaining cloud debt
|
||||||
|
focused on save-before-upload execution, upload form/response handling,
|
||||||
|
prompt/progress lifetime, OpenGL context guarding, downloaded-project open,
|
||||||
|
layer refresh, and action-history reset.
|
||||||
|
|
||||||
Recent 2026-06-13 retained preview reductions continue to narrow DEBT-0036:
|
Recent 2026-06-13 retained preview reductions continue to narrow DEBT-0036:
|
||||||
`NodeStrokePreview::draw_stroke_immediate()` now also routes
|
`NodeStrokePreview::draw_stroke_immediate()` now also routes
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ auditable steps rather than by subjective estimates.
|
|||||||
| Renderer boundary and OpenGL parity | 15 | 11 | Live render/export/readback paths execute through renderer interfaces with parity checks. |
|
| Renderer boundary and OpenGL parity | 15 | 11 | Live render/export/readback paths execute through renderer interfaces with parity checks. |
|
||||||
| Platform and package parity | 10 | 8 | Required platforms have root CMake/package validation and injected platform services. |
|
| Platform and package parity | 10 | 8 | Required platforms have root CMake/package validation and injected platform services. |
|
||||||
| Hardening and future backend readiness | 10 | 4 | Edge, fuzz, golden, stress, and backend-lab gates exist for high-risk paths. |
|
| Hardening and future backend readiness | 10 | 4 | Edge, fuzz, golden, stress, and backend-lab gates exist for high-risk paths. |
|
||||||
| **Total** | **100** | **66** | Only completed tasks below may change this number. |
|
| **Total** | **100** | **67** | Only completed tasks below may change this number. |
|
||||||
|
|
||||||
When updating `Current`, add a dated note under "Completed Task Log" with the
|
When updating `Current`, add a dated note under "Completed Task Log" with the
|
||||||
task id, points moved, validation command, and commit hash.
|
task id, points moved, validation command, and commit hash.
|
||||||
@@ -370,6 +370,46 @@ Completed Task Log:
|
|||||||
| --- | --- | ---: | --- | --- |
|
| --- | --- | ---: | --- | --- |
|
||||||
| 2026-06-15 | ADP-008 | +1 legacy adapter retirement | `ctest --preset desktop-fast --build-config Debug -R "pp_ui_core_node_lifetime\|pp_ui_core_overlay_lifetime" --output-on-failure`; `MSBuild.exe out\build\windows-msvc-default\tests\pp_app_core_document_cloud_tests.vcxproj /p:Configuration=Debug /p:Platform=x64`; `D:\Dev\panopainter\out\build\windows-msvc-default\tests\Debug\pp_app_core_document_cloud_tests.exe`; `MSBuild.exe out\build\windows-msvc-default\panopainter_app.vcxproj /p:Configuration=Debug /p:Platform=x64` | `5bf0a4f6` |
|
| 2026-06-15 | ADP-008 | +1 legacy adapter retirement | `ctest --preset desktop-fast --build-config Debug -R "pp_ui_core_node_lifetime\|pp_ui_core_overlay_lifetime" --output-on-failure`; `MSBuild.exe out\build\windows-msvc-default\tests\pp_app_core_document_cloud_tests.vcxproj /p:Configuration=Debug /p:Platform=x64`; `D:\Dev\panopainter\out\build\windows-msvc-default\tests\Debug\pp_app_core_document_cloud_tests.exe`; `MSBuild.exe out\build\windows-msvc-default\panopainter_app.vcxproj /p:Configuration=Debug /p:Platform=x64` | `5bf0a4f6` |
|
||||||
|
|
||||||
|
### ADP-009 - Move Cloud Transfer Helpers To Legacy Cloud Services
|
||||||
|
|
||||||
|
Status: Done
|
||||||
|
Score: +1 legacy adapter retirement
|
||||||
|
Debt: `DEBT-0038`
|
||||||
|
Scope: `src/legacy_cloud_services.*`, `src/app.cpp`, `src/app.h`,
|
||||||
|
cloud transfer helper path only
|
||||||
|
|
||||||
|
Goal:
|
||||||
|
|
||||||
|
Move the retained upload/download CURL execution off `App` ownership and into
|
||||||
|
`src/legacy_cloud_services.*` so the cloud bridge owns the live transfer helper
|
||||||
|
path directly without changing prompt flow, TLS policy, progress callbacks, or
|
||||||
|
downloaded-project refresh behavior.
|
||||||
|
|
||||||
|
Done Checks:
|
||||||
|
|
||||||
|
- Live cloud upload/download behavior stays unchanged for the retained adapter
|
||||||
|
path.
|
||||||
|
- `App::upload` and `App::download` no longer own the retained CURL setup and
|
||||||
|
progress callback execution.
|
||||||
|
- `src/legacy_cloud_services.*` owns the retained upload/download transfer
|
||||||
|
helpers directly, and `DEBT-0038` describes the reduced remaining cloud
|
||||||
|
bridge surface.
|
||||||
|
|
||||||
|
Validation:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
ctest --preset desktop-fast --build-config Debug -R "pp_app_core_document_cloud" --output-on-failure
|
||||||
|
& 'C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe' out\build\windows-msvc-default\tests\pp_app_core_document_cloud_tests.vcxproj /p:Configuration=Debug /p:Platform=x64
|
||||||
|
& 'C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe' out\build\windows-msvc-default\panopainter_app.vcxproj /p:Configuration=Debug /p:Platform=x64
|
||||||
|
.\out\build\windows-msvc-default\tests\Debug\pp_app_core_document_cloud_tests.exe
|
||||||
|
```
|
||||||
|
|
||||||
|
Completed Task Log:
|
||||||
|
|
||||||
|
| Date | Task | Score | Validation | Commit |
|
||||||
|
| --- | --- | ---: | --- | --- |
|
||||||
|
| 2026-06-15 | ADP-009 | +1 legacy adapter retirement | `ctest --preset desktop-fast --build-config Debug -R "pp_app_core_document_cloud" --output-on-failure`; `MSBuild.exe out\build\windows-msvc-default\tests\pp_app_core_document_cloud_tests.vcxproj /p:Configuration=Debug /p:Platform=x64`; `MSBuild.exe out\build\windows-msvc-default\panopainter_app.vcxproj /p:Configuration=Debug /p:Platform=x64`; `.\out\build\windows-msvc-default\tests\Debug\pp_app_core_document_cloud_tests.exe` | `(pending)` |
|
||||||
|
|
||||||
Completed Task Log:
|
Completed Task Log:
|
||||||
|
|
||||||
| Date | Task | Score | Validation | Commit |
|
| Date | Task | Score | Validation | Commit |
|
||||||
|
|||||||
121
src/app.cpp
121
src/app.cpp
@@ -226,77 +226,6 @@ void App::initLog()
|
|||||||
LOG("load preferences failed");
|
LOG("load preferences failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
#if WITH_CURL
|
|
||||||
int progress_callback_download(void *clientp, curl_off_t dltotal,
|
|
||||||
curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow)
|
|
||||||
{
|
|
||||||
(void)ultotal;
|
|
||||||
(void)ulnow;
|
|
||||||
auto* progress = static_cast<std::function<void(float)>*>(clientp);
|
|
||||||
const auto plan = pp::app::plan_cloud_transfer_progress(
|
|
||||||
static_cast<std::int64_t>(dltotal),
|
|
||||||
static_cast<std::int64_t>(dlnow));
|
|
||||||
if (progress != nullptr && *progress && plan.notify)
|
|
||||||
(*progress)(plan.fraction);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int progress_callback_upload(void *clientp, curl_off_t dltotal,
|
|
||||||
curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow)
|
|
||||||
{
|
|
||||||
(void)dltotal;
|
|
||||||
(void)dlnow;
|
|
||||||
auto* progress = static_cast<std::function<void(float)>*>(clientp);
|
|
||||||
const auto plan = pp::app::plan_cloud_transfer_progress(
|
|
||||||
static_cast<std::int64_t>(ultotal),
|
|
||||||
static_cast<std::int64_t>(ulnow));
|
|
||||||
if (progress != nullptr && *progress && plan.notify)
|
|
||||||
(*progress)(plan.fraction);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif //CURL
|
|
||||||
|
|
||||||
void App::download(std::string url, std::string dest_filepath, std::function<void(float)> progress)
|
|
||||||
{
|
|
||||||
#if WITH_CURL
|
|
||||||
const auto plan = pp::app::plan_cloud_download_transfer(
|
|
||||||
url,
|
|
||||||
dest_filepath,
|
|
||||||
progress != nullptr,
|
|
||||||
disables_network_tls_verification());
|
|
||||||
if (plan.action != pp::app::CloudTransferAction::start_transfer) {
|
|
||||||
LOG("download skipped: invalid transfer request");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
CURL *curl = curl_easy_init();
|
|
||||||
if (curl)
|
|
||||||
{
|
|
||||||
FILE* fp = fopen(dest_filepath.c_str(), "wb");
|
|
||||||
if (fp == nullptr) {
|
|
||||||
LOG("download failed to open destination %s", dest_filepath.c_str());
|
|
||||||
curl_easy_cleanup(curl);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
LOG("download %s to %s", url.c_str(), dest_filepath.c_str());
|
|
||||||
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
|
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_data_write);
|
|
||||||
if (plan.disable_tls_verification)
|
|
||||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
|
|
||||||
if (plan.enable_progress)
|
|
||||||
{
|
|
||||||
curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, progress_callback_download);
|
|
||||||
curl_easy_setopt(curl, CURLOPT_XFERINFODATA, &progress);
|
|
||||||
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
|
|
||||||
}
|
|
||||||
auto err = curl_easy_perform(curl);
|
|
||||||
curl_easy_cleanup(curl);
|
|
||||||
fclose(fp);
|
|
||||||
}
|
|
||||||
#endif //CURL
|
|
||||||
}
|
|
||||||
|
|
||||||
bool App::check_license()
|
bool App::check_license()
|
||||||
{
|
{
|
||||||
return true; // TODO: for distribuiton only
|
return true; // TODO: for distribuiton only
|
||||||
@@ -331,56 +260,6 @@ bool App::check_license()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void App::upload(std::string filename, std::string name, std::function<void(float)> progress)
|
|
||||||
{
|
|
||||||
#if WITH_CURL
|
|
||||||
const auto plan = pp::app::plan_cloud_upload_transfer(
|
|
||||||
filename,
|
|
||||||
progress != nullptr,
|
|
||||||
disables_network_tls_verification());
|
|
||||||
if (plan.action != pp::app::CloudTransferAction::start_transfer) {
|
|
||||||
LOG("upload skipped: invalid transfer request");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
CURL *curl;
|
|
||||||
|
|
||||||
struct curl_httppost *formpost = NULL;
|
|
||||||
struct curl_httppost *lastptr = NULL;
|
|
||||||
|
|
||||||
//curl_global_init(CURL_GLOBAL_ALL);
|
|
||||||
|
|
||||||
curl_formadd(&formpost,
|
|
||||||
&lastptr,
|
|
||||||
CURLFORM_COPYNAME, "fileToUpload",
|
|
||||||
CURLFORM_FILE, filename.c_str(),
|
|
||||||
CURLFORM_END);
|
|
||||||
|
|
||||||
curl = curl_easy_init();
|
|
||||||
std::string res;
|
|
||||||
|
|
||||||
if (curl)
|
|
||||||
{
|
|
||||||
std::string url = "https://panopainter.com/cloud/cloud-upl.php?name=" + name;
|
|
||||||
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
|
||||||
curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
|
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &res);
|
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_data_handler);
|
|
||||||
if (plan.disable_tls_verification)
|
|
||||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
|
|
||||||
if (plan.enable_progress)
|
|
||||||
{
|
|
||||||
curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, progress_callback_upload);
|
|
||||||
curl_easy_setopt(curl, CURLOPT_XFERINFODATA, &progress);
|
|
||||||
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
|
|
||||||
}
|
|
||||||
auto err = curl_easy_perform(curl);
|
|
||||||
std::cout << "\n\nUPLOAD RESULT\n" << res << "\n\n\n";
|
|
||||||
curl_easy_cleanup(curl);
|
|
||||||
}
|
|
||||||
#endif //CURL
|
|
||||||
}
|
|
||||||
|
|
||||||
void App::init()
|
void App::init()
|
||||||
{
|
{
|
||||||
LOG("Screen Resolution: %dx%d", (int)width, (int)height);
|
LOG("Screen Resolution: %dx%d", (int)width, (int)height);
|
||||||
|
|||||||
@@ -319,10 +319,6 @@ public:
|
|||||||
void cloud_upload();
|
void cloud_upload();
|
||||||
void cloud_upload_all();
|
void cloud_upload_all();
|
||||||
void cloud_browse();
|
void cloud_browse();
|
||||||
void upload(std::string filename, std::string name = "",
|
|
||||||
std::function<void(float)> progress = nullptr);
|
|
||||||
void download(std::string url, std::string dest_filepath,
|
|
||||||
std::function<void(float)> progress = nullptr);
|
|
||||||
bool check_license();
|
bool check_license();
|
||||||
|
|
||||||
std::shared_ptr<NodeProgressBar> show_progress(const std::string& title, int total = 0);
|
std::shared_ptr<NodeProgressBar> show_progress(const std::string& title, int total = 0);
|
||||||
|
|||||||
@@ -14,6 +14,131 @@
|
|||||||
namespace pp::panopainter {
|
namespace pp::panopainter {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
#if WITH_CURL
|
||||||
|
int progress_callback_download(void* clientp, curl_off_t dltotal,
|
||||||
|
curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow)
|
||||||
|
{
|
||||||
|
(void)ultotal;
|
||||||
|
(void)ulnow;
|
||||||
|
auto* progress = static_cast<std::function<void(float)>*>(clientp);
|
||||||
|
const auto plan = pp::app::plan_cloud_transfer_progress(
|
||||||
|
static_cast<std::int64_t>(dltotal),
|
||||||
|
static_cast<std::int64_t>(dlnow));
|
||||||
|
if (progress != nullptr && *progress && plan.notify)
|
||||||
|
(*progress)(plan.fraction);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int progress_callback_upload(void* clientp, curl_off_t dltotal,
|
||||||
|
curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow)
|
||||||
|
{
|
||||||
|
(void)dltotal;
|
||||||
|
(void)dlnow;
|
||||||
|
auto* progress = static_cast<std::function<void(float)>*>(clientp);
|
||||||
|
const auto plan = pp::app::plan_cloud_transfer_progress(
|
||||||
|
static_cast<std::int64_t>(ultotal),
|
||||||
|
static_cast<std::int64_t>(ulnow));
|
||||||
|
if (progress != nullptr && *progress && plan.notify)
|
||||||
|
(*progress)(plan.fraction);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void execute_cloud_download_transfer(
|
||||||
|
App& app,
|
||||||
|
std::string url,
|
||||||
|
std::string dest_filepath,
|
||||||
|
std::function<void(float)> progress)
|
||||||
|
{
|
||||||
|
const auto plan = pp::app::plan_cloud_download_transfer(
|
||||||
|
url,
|
||||||
|
dest_filepath,
|
||||||
|
progress != nullptr,
|
||||||
|
app.disables_network_tls_verification());
|
||||||
|
if (plan.action != pp::app::CloudTransferAction::start_transfer) {
|
||||||
|
LOG("download skipped: invalid transfer request");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CURL* curl = curl_easy_init();
|
||||||
|
if (curl)
|
||||||
|
{
|
||||||
|
FILE* fp = fopen(dest_filepath.c_str(), "wb");
|
||||||
|
if (fp == nullptr) {
|
||||||
|
LOG("download failed to open destination %s", dest_filepath.c_str());
|
||||||
|
curl_easy_cleanup(curl);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LOG("download %s to %s", url.c_str(), dest_filepath.c_str());
|
||||||
|
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
||||||
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_data_write);
|
||||||
|
if (plan.disable_tls_verification)
|
||||||
|
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
|
||||||
|
if (plan.enable_progress)
|
||||||
|
{
|
||||||
|
curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, progress_callback_download);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_XFERINFODATA, &progress);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
|
||||||
|
}
|
||||||
|
auto err = curl_easy_perform(curl);
|
||||||
|
curl_easy_cleanup(curl);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void execute_cloud_upload_transfer(
|
||||||
|
App& app,
|
||||||
|
std::string filename,
|
||||||
|
std::string name,
|
||||||
|
std::function<void(float)> progress)
|
||||||
|
{
|
||||||
|
const auto plan = pp::app::plan_cloud_upload_transfer(
|
||||||
|
filename,
|
||||||
|
progress != nullptr,
|
||||||
|
app.disables_network_tls_verification());
|
||||||
|
if (plan.action != pp::app::CloudTransferAction::start_transfer) {
|
||||||
|
LOG("upload skipped: invalid transfer request");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CURL* curl;
|
||||||
|
|
||||||
|
struct curl_httppost* formpost = NULL;
|
||||||
|
struct curl_httppost* lastptr = NULL;
|
||||||
|
|
||||||
|
//curl_global_init(CURL_GLOBAL_ALL);
|
||||||
|
|
||||||
|
curl_formadd(&formpost,
|
||||||
|
&lastptr,
|
||||||
|
CURLFORM_COPYNAME, "fileToUpload",
|
||||||
|
CURLFORM_FILE, filename.c_str(),
|
||||||
|
CURLFORM_END);
|
||||||
|
|
||||||
|
curl = curl_easy_init();
|
||||||
|
std::string res;
|
||||||
|
|
||||||
|
if (curl)
|
||||||
|
{
|
||||||
|
std::string url = "https://panopainter.com/cloud/cloud-upl.php?name=" + name;
|
||||||
|
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
||||||
|
curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &res);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_data_handler);
|
||||||
|
if (plan.disable_tls_verification)
|
||||||
|
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
|
||||||
|
if (plan.enable_progress)
|
||||||
|
{
|
||||||
|
curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, progress_callback_upload);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_XFERINFODATA, &progress);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
|
||||||
|
}
|
||||||
|
auto err = curl_easy_perform(curl);
|
||||||
|
std::cout << "\n\nUPLOAD RESULT\n" << res << "\n\n\n";
|
||||||
|
curl_easy_cleanup(curl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif //WITH_CURL
|
||||||
|
|
||||||
class LegacyCloudServices final : public pp::app::CloudServices {
|
class LegacyCloudServices final : public pp::app::CloudServices {
|
||||||
public:
|
public:
|
||||||
explicit LegacyCloudServices(App& app) noexcept
|
explicit LegacyCloudServices(App& app) noexcept
|
||||||
@@ -41,7 +166,7 @@ public:
|
|||||||
const auto progress_plan = pp::app::plan_cloud_upload_progress_dialog();
|
const auto progress_plan = pp::app::plan_cloud_upload_progress_dialog();
|
||||||
auto pb = app->show_progress(progress_plan.title, progress_plan.total);
|
auto pb = app->show_progress(progress_plan.title, progress_plan.total);
|
||||||
|
|
||||||
app->upload(app->doc_path, app->doc_filename, [pb](float p) {
|
execute_cloud_upload_transfer(*app, app->doc_path, app->doc_filename, [pb](float p) {
|
||||||
pb->set_progress(p);
|
pb->set_progress(p);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -77,7 +202,7 @@ public:
|
|||||||
for (const auto& n : names)
|
for (const auto& n : names)
|
||||||
{
|
{
|
||||||
std::string path = app_.data_path + "/" + n;
|
std::string path = app_.data_path + "/" + n;
|
||||||
app_.upload(path);
|
execute_cloud_upload_transfer(app_, path, std::string(), std::function<void(float)> {});
|
||||||
|
|
||||||
if (bulk_progress_) {
|
if (bulk_progress_) {
|
||||||
bulk_progress_->increment();
|
bulk_progress_->increment();
|
||||||
@@ -116,7 +241,7 @@ public:
|
|||||||
*app,
|
*app,
|
||||||
pp::app::plan_cloud_download_progress_prompt());
|
pp::app::plan_cloud_download_progress_prompt());
|
||||||
std::string url = "https://panopainter.com/cloud/cloud-dwl.php?file=" + request.selected_file;
|
std::string url = "https://panopainter.com/cloud/cloud-dwl.php?file=" + request.selected_file;
|
||||||
app->download(url, request.selected_path, [m](float p) {
|
execute_cloud_download_transfer(*app, url, request.selected_path, [m](float p) {
|
||||||
const auto progress = pp::app::format_cloud_download_progress_message(p);
|
const auto progress = pp::app::format_cloud_download_progress_message(p);
|
||||||
m->m_message->set_text(progress.c_str());
|
m->m_message->set_text(progress.c_str());
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user