Plan cloud dialog metadata

This commit is contained in:
2026-06-05 08:14:11 +02:00
parent e5526c6d0a
commit f46839bf5c
8 changed files with 190 additions and 26 deletions

View File

@@ -777,13 +777,15 @@ Known local toolchain state:
renderer API to OpenGL token mapping and command-planning contracts used by
the OpenGL parity work.
- `pano_cli plan-cloud-upload` exposes `pp_app_core` cloud upload availability,
new-document warning, publish prompt, and save-before-upload planning as JSON;
new-document warning, publish prompt, prompt title/message/captions, and
save-before-upload planning as JSON;
the live cloud upload command consumes the same start contract before
reaching legacy UI, canvas save, and network upload execution.
- `pano_cli plan-cloud-upload-all` exposes bulk cloud upload file-count,
progress UI availability, and progress-total clamping as JSON; the live
upload-all command consumes the same contract before reaching legacy asset
file listing, OpenGL context guard, progress UI, and network upload
progress UI availability, progress-total clamping, and progress dialog
metadata as JSON; the live upload-all command consumes the same contract
before reaching legacy asset file listing, OpenGL context guard, progress UI,
and network upload
execution.
- `pano_cli plan-cloud-browse` exposes `pp_app_core` cloud browse availability
and selected-file download planning as JSON; the live cloud browse command
@@ -794,7 +796,10 @@ Known local toolchain state:
live paths on the `pp_app_core` `CloudServices` contract while the app-owned
curl upload/download/license helpers now ask `PlatformServices` for TLS
verification policy and retained dialog/network curl sites use the shared
default platform TLS helper. Legacy save-before-upload, progress/message UI,
default platform TLS helper. Cloud upload warning/publish/success copy, bulk
upload progress title, and download-progress copy now come from
`pp_app_core` dialog/progress plans before retained `NodeMessageBox` and
progress-bar execution. Legacy save-before-upload, progress/message UI,
network upload/download helper ownership, OpenGL context guarding,
`NodeDialogCloud`, project open, layer refresh, and action-history reset
remain tracked by `DEBT-0038`.

View File

@@ -161,6 +161,15 @@ agent or engineer to remove them without reconstructing context from chat.
progress-callback, and zero/overrun progress cases for automation. CURL
ownership, response/error handling, progress UI, cloud dialog/document
execution, and injected network service work remain open under DEBT-0038.
- 2026-06-05: DEBT-0038 was narrowed again. Cloud upload warning/publish/
success prompts, upload/bulk progress dialog titles, download-progress prompt
metadata, and formatted download progress text now live in tested
`pp_app_core` plans consumed by `src/legacy_cloud_services.*`; existing
`pano_cli plan-cloud-upload`, `pano_cli plan-cloud-upload-all`, and
`pano_cli plan-cloud-transfer` expose that metadata for automation. Retained
`NodeMessageBox`/progress-bar creation, save-before-upload threading, CURL
ownership, response/error handling, and downloaded-project execution remain
open under DEBT-0038.
- 2026-06-05: DEBT-0058 was opened. App-level progress, message, and input
dialog metadata now lives in tested `pp_app_core` planning consumed by
`App::show_progress`, `App::message_box`, `App::input_box`, and
@@ -217,7 +226,7 @@ agent or engineer to remove them without reconstructing context from chat.
| DEBT-0035 | Open | Modernization | Main toolbar/status command planning and execution dispatch now consume pure `pp_app_core` through `App::init_toolbar_main`, `pano_cli plan-main-toolbar`, and the `MainToolbarServices` boundary, history/canvas commands now hand off through `HistoryUiServices` and `DocumentCanvasClearServices`, and live execution is centralized in `src/legacy_app_shell_services.*`, but the bridge still opens legacy open/save/settings/message-box dialogs and delegates to legacy history/canvas adapters | Preserve reachable toolbar/status behavior while app shell commands move toward app/document/UI services | `pp_app_core_main_toolbar_tests`; `pano_cli plan-main-toolbar --command undo --undo-count 2`; `pano_cli plan-main-toolbar --command clear-canvas --no-canvas`; `ctest --preset desktop-fast --build-config Debug` | Open/save/settings/message-box routing, undo/redo/clear-history execution, and canvas-clear execution are owned by injected app/document/UI services with `App::init_toolbar_main` acting only as a UI adapter and no legacy toolbar adapter |
| DEBT-0036 | Open | Modernization | `pp_renderer_api`, `pp_paint_renderer`, `pano_cli plan-paint-feedback`, and `pano_cli plan-stroke-composite` can choose backend-neutral complex paint feedback strategies for fixed-function blending, framebuffer-fetch-capable renderers, or ping-pong render targets. OpenGL extension detection now stores `pp::renderer::RenderDeviceFeatures` through `ShaderManager`, using `pp_renderer_gl::query_opengl_capability_detection`, `detect_opengl_feature_state`, and `render_device_features` as the backend conversion point; that feature snapshot now includes float32-linear filtering, so canvas stroke texture format selection, renderer diagnostics, grid lightmap render planning, and grid bake target selection no longer read `ShaderManager::ext_*` flags directly. `pp_paint_renderer::plan_canvas_blend_gate` owns the compatibility mapping from persisted layer/brush blend indices to the extracted stroke-composite planner, and live `Canvas::draw_merge` plus `NodeCanvas` panorama rendering both call it with the stored renderer-neutral feature set for their existing shader-blend gates and destination-copy versus framebuffer-fetch decisions. `pp_paint_renderer::plan_canvas_stroke_feedback` also owns the current destination-feedback decision, and live `Canvas::stroke_draw`, thumbnail layer blending, and `NodeStrokePreview` brush-preview rendering use it for framebuffer-fetch versus destination-copy decisions. The retained `copy_framebuffer_to_texture_2d` utility bridge now routes 2D framebuffer-to-texture copies through tested `pp_renderer_gl` dispatch, retained `RTT::create`/`RTT::destroy` render-target texture parameter setup, optional depth renderbuffer allocation, framebuffer allocation/attachment/status checks, binding restore, and resource deletion now route through tested `pp_renderer_gl` dispatch, retained RTT clear, masked clear with color-write-mask restore, texture bind/unbind, and RGBA8 dirty-region texture writes now route through tested `pp_renderer_gl` dispatch, retained Canvas, NodeCanvas, and NodeStrokePreview texture-unit switches now route through tested active-texture dispatch, retained Canvas, NodeCanvas, NodeStrokePreview, and desktop HMD viewport/scissor/capability execution now route through tested `pp_renderer_gl` dispatch adapters, retained NodeCanvas, CanvasMode, and NodePanelGrid capability-state snapshots now route through tested `pp_renderer_gl` query dispatch, CanvasLayer cube/equirect generation plus frame clears now route blend state, active texture units, viewport execution, color clears, and cube-face framebuffer-to-texture copies through tested `pp_renderer_gl` dispatch adapters, `NodePanelGrid` live heightmap draw and bake setup now route depth/blend state, depth clears, color-write-mask toggles, active texture selection, bake viewport execution, sun-overlay viewport query, and desktop texture-resize readback through tested `pp_renderer_gl` dispatch adapters, retained CanvasMode overlay/mask/transform paths now route active texture, depth/blend state, transform/cut viewport execution, paint-mode blend/depth state snapshots, and canvas-tip pick framebuffer readback through tested `pp_renderer_gl` dispatch adapters, retained simple UI draw paths now share `legacy_ui_gl_dispatch` for blend-state execution, fallback 2D texture unbinds, `NodeViewport` viewport query/restore, color-buffer clears, and clear-color restore, retained `NodeCanvas` plus `NodeStrokePreview` draw-state paths now route viewport query, clear-color query, color-buffer clear, and clear-color restore through tested `pp_renderer_gl` dispatch helpers, and retained `Canvas` plus `CanvasLayer` stroke/object/thumbnail/frame-clear draw-state paths now route saved viewport or clear-color query and restore through the same tested helpers, but actual live stroke rasterization, dual-brush compositing, pattern feedback math, thumbnail layer compositing, brush-preview compositing, and the retained `ShaderManager::ext_*` compatibility fields still use legacy OpenGL canvas/UI execution | Preserve current painting behavior while the renderer boundary matures for OpenGL parity and later Vulkan/Metal experiments | `pp_renderer_api_tests`; `pp_renderer_gl_capabilities_tests`; `pp_paint_renderer_compositor_tests`; `pano_cli plan-paint-feedback --framebuffer-fetch --explicit-transitions --render-only`; `pano_cli plan-paint-feedback --texture-copy`; `pano_cli plan-stroke-composite --stroke-blend 10 --framebuffer-fetch --explicit-transitions --render-only`; `pano_cli plan-stroke-composite --layer-blend 4 --dual-blend --texture-copy`; `ctest --preset desktop-fast --build-config Debug`; `cmake --build --preset windows-msvc-default --config Debug --target PanoPainter` | Live stroke/layer compositing chooses its feedback path through `pp_paint_renderer` and renderer services, with OpenGL golden parity and Vulkan/Metal lab tests covering framebuffer-fetch and ping-pong behavior |
| DEBT-0037 | Open | Modernization | Recording lifecycle/export planning and execution dispatch now consume pure `pp_app_core` through `App::rec_start`, `App::rec_stop`, `App::rec_clear`, `App::rec_export`, `pano_cli plan-recording-session`, and the `RecordingServices` boundary; live execution is centralized in `src/legacy_recording_services.*`, and retained `PBO` allocation/readback/map/unmap/delete operations now route through tested `pp_renderer_gl` dispatch, but the bridge still owns legacy recording thread startup/shutdown, platform recorded-file cleanup, progress UI, retained `App::rec_loop` readback call sites, and `MP4Encoder::write_mp4` execution | Preserve current timelapse/MP4 behavior while recording moves toward app/document/renderer/video services | `pp_app_core_document_recording_tests`; `pp_renderer_gl_capabilities_tests`; `pano_cli plan-recording-session --running --frame-count 12`; `pano_cli plan-recording-session --platform-clears-files`; `ctest --preset desktop-fast --build-config Debug` | Recording thread lifecycle, frame readback scheduling, platform cleanup, progress reporting, and MP4 writing are owned by injected app/renderer/video services with `App` methods acting only as adapters |
| DEBT-0038 | Open | Modernization | Cloud upload/browse/bulk planning and execution dispatch now consume pure `pp_app_core` through `App::cloud_upload`, `App::cloud_upload_all`, `App::cloud_browse`, `pano_cli plan-cloud-upload`, `pano_cli plan-cloud-upload-all`, `pano_cli plan-cloud-browse`, and the `CloudServices` boundary; live execution is centralized in `src/legacy_cloud_services.*`, the app-owned `upload`/`download` CURL helpers now consume `pp_app_core` cloud transfer request/progress planning and the platform TLS-verification bypass policy before retained CURL setup, `pano_cli plan-cloud-transfer` exposes the same missing endpoint, TLS policy, progress-callback, and progress fraction guards, and retained `Asset::open_url`, `LogRemote::net_init`, and `NodeDialogCloud::load_thumbs_thread` curl sites consume the `pp_platform_api` default TLS policy helper instead of spelling Android branches locally, but the bridge still uses legacy save-before-upload, app-owned curl helpers instead of an injected network service, upload form construction, response/error handling, progress/message UI, OpenGL context guarding, `NodeDialogCloud`, `Canvas` project open, layer refresh, and `ActionManager` reset | Preserve current cloud behavior while cloud/network/document import flows move toward app/document/platform services | `pp_app_core_document_cloud_tests`; `pp_platform_api_tests`; `pano_cli plan-cloud-upload --new-document --unsaved`; `pano_cli plan-cloud-browse --selected-file demo.ppi`; `pano_cli plan-cloud-upload-all --file-count 3`; `pano_cli plan-cloud-transfer --direction download --progress --disable-tls-verification`; `ctest --preset desktop-fast --build-config Debug` | Cloud upload/download, TLS policy, save-before-upload, progress reporting, cloud browse dialog, downloaded project opening, layer refresh, OpenGL context ownership, and action-history reset are owned by injected app/document/network/platform/renderer services with `App` methods acting only as adapters |
| DEBT-0038 | Open | Modernization | Cloud upload/browse/bulk planning, cloud prompt/progress metadata, and execution dispatch now consume pure `pp_app_core` through `App::cloud_upload`, `App::cloud_upload_all`, `App::cloud_browse`, `pano_cli plan-cloud-upload`, `pano_cli plan-cloud-upload-all`, `pano_cli plan-cloud-browse`, `pano_cli plan-cloud-transfer`, and the `CloudServices` boundary; live execution is centralized in `src/legacy_cloud_services.*`, the app-owned `upload`/`download` CURL helpers now consume `pp_app_core` cloud transfer request/progress planning and the platform TLS-verification bypass policy before retained CURL setup, upload warning/publish/success prompts, upload/bulk progress dialog titles, download-progress prompt metadata, and formatted download progress text come from tested app-core plans, and retained `Asset::open_url`, `LogRemote::net_init`, and `NodeDialogCloud::load_thumbs_thread` curl sites consume the `pp_platform_api` default TLS policy helper instead of spelling Android branches locally, but the bridge still uses legacy save-before-upload, app-owned curl helpers instead of an injected network service, upload form construction, response/error handling, retained `NodeMessageBox`/progress-bar execution, OpenGL context guarding, `NodeDialogCloud`, `Canvas` project open, layer refresh, and `ActionManager` reset | Preserve current cloud behavior while cloud/network/document import flows move toward app/document/platform services | `pp_app_core_document_cloud_tests`; `pp_platform_api_tests`; `pano_cli plan-cloud-upload --new-document --unsaved`; `pano_cli plan-cloud-browse --selected-file demo.ppi`; `pano_cli plan-cloud-upload-all --file-count 3`; `pano_cli plan-cloud-transfer --direction download --progress --disable-tls-verification`; `ctest --preset desktop-fast --build-config Debug` | Cloud upload/download, TLS policy, save-before-upload, progress reporting, cloud browse dialog, downloaded project opening, layer refresh, OpenGL context ownership, and action-history reset are owned by injected app/document/network/platform/renderer services with `App` methods acting only as adapters |
| DEBT-0039 | Open | Modernization | Document-open planning and execution dispatch now consume pure `pp_app_core` through `App::open_document`, `pano_cli plan-open-route`, `DocumentOpenServices`, and `src/legacy_document_open_services.*`, but the bridge still opens ABR/PPBR import prompts before delegating import execution to `src/legacy_brush_package_import_services.*`, applies unsaved-project discard prompts, calls legacy project-open execution, refreshes layer UI, updates the app title, and clears legacy history directly | Preserve current file-open/import behavior while document loading and brush import move toward app/document/asset/UI services | `pp_app_core_document_route_tests`; `pp_app_core_document_session_tests`; `pano_cli plan-open-route --path D:/Paint/Scenes/demo.ppi --unsaved`; `pano_cli plan-open-route --path D:/Paint/Brushes/clouds.ABR --unsaved`; `ctest --preset desktop-fast --build-config Debug` | Brush import prompting, project-open execution, unsaved-project discard prompting, layer refresh, title updates, and history clearing are owned by injected app/document/asset/UI services with `App::open_document` acting only as an adapter |
| DEBT-0040 | Open | Modernization | Close request, document save, save-before-workflow planning/execution dispatch, and close/save-before/save-error prompt metadata now consume pure `pp_app_core` through `App::request_close`, `App::save_document`, `App::continue_document_workflow_after_optional_save`, `pano_cli simulate-app-session`, `pano_cli plan-document-session-prompt`, `DocumentSaveServices`, `CloseRequestServices`, `DocumentWorkflowServices`, and `src/legacy_document_session_services.*`; Save dialog working-directory picker visibility/path formatting now dispatches through `PlatformServices`, but the bridge still opens retained `NodeMessageBox`/save dialogs, wires callbacks directly, calls `Canvas::I->project_save`, mutates the unsaved flag on close confirmation, invokes native app close, and routes save-version through the retained legacy dialog | Preserve current close/save/dirty-workflow behavior while document session execution moves toward app/document/UI/platform services | `pp_app_core_document_session_tests`; `pp_platform_api_tests`; `pano_cli plan-document-session-prompt --kind close-unsaved`; `pano_cli plan-document-session-prompt --kind save-before-workflow`; `pano_cli simulate-app-session --unsaved --save-intent save-dirty-version`; `pano_cli simulate-app-session --no-canvas`; `pano_cli plan-document-file --work-dir D:/Paint --name demo --target-exists`; `pano_cli plan-document-version --directory D:/Paint --doc-name demo.01 --existing-path D:/Paint/demo.02.ppi`; `ctest --preset desktop-fast --build-config Debug` | Close prompt execution, native close requests, dirty-workflow save prompts, existing-project saves, save dialogs, save-version execution, and unsaved-flag mutation are owned by injected app/document/UI/platform services with `App` methods acting only as adapters |
| DEBT-0041 | Open | Modernization | Accepted new-document planning/execution dispatch and new-document overwrite prompt metadata now consume pure `pp_app_core` through `App::dialog_newdoc`, `pano_cli plan-new-document`, `pano_cli plan-document-session-prompt`, `NewDocumentServices`, and `src/legacy_document_session_services.*`; New Document dialog working-directory picker visibility/path formatting now dispatches through `PlatformServices`, but the bridge still mutates legacy app document fields, clears legacy layer UI, resizes legacy `Canvas`, clears legacy history, creates the default layer through legacy UI, mutates unsaved/new-document flags, updates the title, creates retained `NodeMessageBox` overwrite prompts, and handles keyboard/dialog cleanup directly | Preserve current New Document dialog behavior while document creation moves toward app/document/UI services | `pp_app_core_document_session_tests`; `pp_platform_api_tests`; `pano_cli plan-new-document --work-dir D:/Paint --name demo --resolution-index 3`; `pano_cli plan-new-document --work-dir D:/Paint --name demo --resolution-index 3 --target-exists`; `pano_cli plan-document-session-prompt --kind new-document-overwrite`; `pano_cli simulate-app-session --save-intent save`; `ctest --preset desktop-fast --build-config Debug` | New document creation, overwrite confirmation, canvas/document allocation, default layer creation, history clearing, title updates, dirty/new-document state, and keyboard/dialog cleanup are owned by injected app/document/UI services with `App::dialog_newdoc` acting only as a UI adapter |

View File

@@ -1644,6 +1644,15 @@ Results:
before retained CURL setup.
- Android arm64 headless `pp_app_core`, `pano_cli`, and
`pp_app_core_document_cloud_tests` built after the cloud transfer slice.
- `PanoPainter`, `pp_app_core_document_cloud_tests`, and `pano_cli` built after
cloud upload warning/publish/success prompts, bulk upload progress dialogs,
and download-progress messages moved to tested `pp_app_core` metadata plans.
- Focused cloud metadata CTest coverage passed for
`pp_app_core_document_cloud_tests` and representative
`pano_cli_plan_cloud_*` smoke tests, including prompt titles/captions,
progress-dialog titles, and formatted download progress messages.
- Android arm64 headless `pp_app_core`, `pano_cli`, and
`pp_app_core_document_cloud_tests` built after the cloud metadata slice.
- `PanoPainter`, `pp_app_core_document_cloud_tests`, and `pano_cli` built after
live cloud upload, bulk upload, and browse/download execution moved behind
the `CloudServices` boundary and `src/legacy_cloud_services.*`.

View File

@@ -1,7 +1,9 @@
#pragma once
#include "app_core/app_dialog.h"
#include "foundation/result.h"
#include <cstdio>
#include <cstddef>
#include <cstdint>
#include <limits>
@@ -66,6 +68,61 @@ struct CloudTransferProgressPlan {
float fraction = 0.0F;
};
[[nodiscard]] inline AppMessageDialogPlan plan_cloud_save_required_prompt()
{
return plan_app_message_dialog(
"Warning",
"This document needs to be saved before upload.",
false);
}
[[nodiscard]] inline AppMessageDialogPlan plan_cloud_publish_prompt()
{
return plan_app_message_dialog(
"Publish document",
"Would you like to upload to the public domain?",
true,
"Yes",
"No");
}
[[nodiscard]] inline AppMessageDialogPlan plan_cloud_upload_success_prompt()
{
return plan_app_message_dialog(
"Success",
"This document has been succesfully uploaded.",
false);
}
[[nodiscard]] inline AppProgressDialogPlan plan_cloud_upload_progress_dialog()
{
return plan_app_progress_dialog("Uploading", 0);
}
[[nodiscard]] inline AppProgressDialogPlan plan_cloud_bulk_upload_progress_dialog(int progress_total)
{
return plan_app_progress_dialog("Export Pano Image", progress_total);
}
[[nodiscard]] inline AppMessageDialogPlan plan_cloud_download_progress_prompt()
{
return plan_app_message_dialog(
"Downloading",
"Download in progress",
true);
}
[[nodiscard]] inline std::string format_cloud_download_progress_message(float progress_fraction)
{
char buffer[64] {};
std::snprintf(
buffer,
sizeof(buffer),
"Download in progress %.2f%%",
progress_fraction * 100.0F);
return buffer;
}
class CloudServices {
public:
virtual ~CloudServices() = default;

View File

@@ -12,6 +12,20 @@
namespace pp::panopainter {
namespace {
void apply_cloud_message_box_plan(
NodeMessageBox& msgbox,
const pp::app::AppMessageDialogPlan& plan)
{
msgbox.m_title->set_text(plan.title.c_str());
msgbox.m_message->set_text(plan.message.c_str());
msgbox.btn_ok->m_text->set_text(plan.ok_caption.c_str());
if (plan.show_cancel) {
msgbox.btn_cancel->m_text->set_text(plan.cancel_caption.c_str());
} else {
msgbox.btn_cancel->destroy();
}
}
class LegacyCloudServices final : public pp::app::CloudServices {
public:
explicit LegacyCloudServices(App& app) noexcept
@@ -21,7 +35,8 @@ public:
void show_save_required_warning() override
{
app_.message_box("Warning", "This document needs to be saved before upload.");
const auto plan = pp::app::plan_cloud_save_required_prompt();
app_.message_box(plan.title, plan.message, plan.show_cancel);
}
void prompt_publish(bool save_before_upload) override
@@ -35,19 +50,20 @@ public:
Canvas::I->project_save_thread(app->doc_path, true);
}
auto pb = app->show_progress("Uploading");
const auto progress_plan = pp::app::plan_cloud_upload_progress_dialog();
auto pb = app->show_progress(progress_plan.title, progress_plan.total);
app->upload(app->doc_path, app->doc_filename, [pb](float p) {
pb->set_progress(p);
});
pb->destroy();
app->message_box("Success", "This document has been succesfully uploaded.");
const auto success_plan = pp::app::plan_cloud_upload_success_prompt();
app->message_box(success_plan.title, success_plan.message, success_plan.show_cancel);
};
auto m = app_.message_box("Publish document", "Would you like to upload to the public domain?");
m->btn_ok->m_text->set_text("Yes");
m->btn_cancel->m_text->set_text("No");
const auto prompt_plan = pp::app::plan_cloud_publish_prompt();
auto m = app_.message_box(prompt_plan.title, prompt_plan.message, prompt_plan.show_cancel);
m->btn_ok->on_click = [m, upload_thread](Node*) {
std::thread(upload_thread).detach();
m->destroy();
@@ -61,7 +77,8 @@ public:
{
bulk_progress_.reset();
if (show_progress) {
bulk_progress_ = app_.show_progress("Export Pano Image", progress_total);
const auto progress_plan = pp::app::plan_cloud_bulk_upload_progress_dialog(progress_total);
bulk_progress_ = app_.show_progress(progress_plan.title, progress_plan.total);
}
}
@@ -114,13 +131,11 @@ public:
BT_SetTerminate();
auto* m = app->layout[app->main_id]->add_child<NodeMessageBox>();
m->m_title->set_text("Downloading");
m->m_message->set_text("Download in progress");
apply_cloud_message_box_plan(*m, pp::app::plan_cloud_download_progress_prompt());
std::string url = "https://panopainter.com/cloud/cloud-dwl.php?file=" + request.selected_file;
app->download(url, request.selected_path, [m](float p) {
static char progress[256];
sprintf(progress, "Download in progress %.2f%%", p * 100.f);
m->m_message->set_text(progress);
const auto progress = pp::app::format_cloud_download_progress_message(p);
m->m_message->set_text(progress.c_str());
});
const auto reset_status = execute_legacy_canvas_camera_reset(*app);

View File

@@ -903,7 +903,7 @@ if(TARGET pano_cli)
COMMAND pano_cli plan-cloud-upload)
set_tests_properties(pano_cli_plan_cloud_upload_clean_smoke PROPERTIES
LABELS "app;integration;desktop-fast"
PASS_REGULAR_EXPRESSION "\"command\":\"plan-cloud-upload\".*\"hasCanvas\":true.*\"newDocument\":false.*\"unsaved\":false.*\"decision\":\"prompt-publish\".*\"saveBeforeUpload\":false")
PASS_REGULAR_EXPRESSION "\"command\":\"plan-cloud-upload\".*\"hasCanvas\":true.*\"newDocument\":false.*\"unsaved\":false.*\"decision\":\"prompt-publish\".*\"saveBeforeUpload\":false.*\"title\":\"Publish document\".*\"okCaption\":\"Yes\".*\"cancelCaption\":\"No\"")
add_test(NAME pano_cli_plan_cloud_upload_unsaved_smoke
COMMAND pano_cli plan-cloud-upload --unsaved)
@@ -915,7 +915,7 @@ if(TARGET pano_cli)
COMMAND pano_cli plan-cloud-upload --new-document --unsaved)
set_tests_properties(pano_cli_plan_cloud_upload_new_document_smoke PROPERTIES
LABELS "app;integration;desktop-fast;fuzz"
PASS_REGULAR_EXPRESSION "\"command\":\"plan-cloud-upload\".*\"newDocument\":true.*\"decision\":\"show-save-required-warning\".*\"saveBeforeUpload\":false")
PASS_REGULAR_EXPRESSION "\"command\":\"plan-cloud-upload\".*\"newDocument\":true.*\"decision\":\"show-save-required-warning\".*\"saveBeforeUpload\":false.*\"title\":\"Warning\".*\"message\":\"This document needs to be saved before upload\\.\".*\"showCancel\":false")
add_test(NAME pano_cli_plan_cloud_upload_no_canvas_smoke
COMMAND pano_cli plan-cloud-upload --no-canvas --new-document --unsaved)
@@ -945,7 +945,7 @@ if(TARGET pano_cli)
COMMAND pano_cli plan-cloud-upload-all --file-count 3)
set_tests_properties(pano_cli_plan_cloud_upload_all_progress_smoke PROPERTIES
LABELS "app;integration;desktop-fast"
PASS_REGULAR_EXPRESSION "\"command\":\"plan-cloud-upload-all\".*\"fileCount\":3.*\"progressUiAvailable\":true.*\"progressTotal\":3.*\"showProgress\":true")
PASS_REGULAR_EXPRESSION "\"command\":\"plan-cloud-upload-all\".*\"fileCount\":3.*\"progressUiAvailable\":true.*\"progressTotal\":3.*\"showProgress\":true.*\"progressDialog\":\\{\"title\":\"Export Pano Image\".*\"total\":3")
add_test(NAME pano_cli_plan_cloud_upload_all_headless_smoke
COMMAND pano_cli plan-cloud-upload-all --file-count 3 --no-progress-ui)
@@ -957,7 +957,7 @@ if(TARGET pano_cli)
COMMAND pano_cli plan-cloud-transfer --direction download --progress --disable-tls-verification --progress-total 100 --progress-current 25)
set_tests_properties(pano_cli_plan_cloud_transfer_download_smoke PROPERTIES
LABELS "app;integration;desktop-fast"
PASS_REGULAR_EXPRESSION "\"command\":\"plan-cloud-transfer\".*\"direction\":\"download\".*\"action\":\"start-transfer\".*\"enableProgress\":true.*\"disableTlsVerification\":true.*\"notify\":true.*\"fraction\":0.25")
PASS_REGULAR_EXPRESSION "\"command\":\"plan-cloud-transfer\".*\"direction\":\"download\".*\"action\":\"start-transfer\".*\"enableProgress\":true.*\"disableTlsVerification\":true.*\"notify\":true.*\"fraction\":0.25.*\"progressPrompt\":\\{\"title\":\"Downloading\".*\"formattedMessage\":\"Download in progress 25.00%\"")
add_test(NAME pano_cli_plan_cloud_transfer_upload_smoke
COMMAND pano_cli plan-cloud-transfer --direction upload --source D:/Paint/demo.ppi --progress-total 10 --progress-current 20)

View File

@@ -157,6 +157,41 @@ void cloud_bulk_upload_clamps_progress_total(pp::tests::Harness& harness)
PP_EXPECT(harness, plan.show_progress);
}
void cloud_dialog_plans_preserve_upload_prompt_metadata(pp::tests::Harness& harness)
{
const auto save_required = pp::app::plan_cloud_save_required_prompt();
const auto publish = pp::app::plan_cloud_publish_prompt();
const auto success = pp::app::plan_cloud_upload_success_prompt();
PP_EXPECT(harness, save_required.title == "Warning");
PP_EXPECT(harness, save_required.message == "This document needs to be saved before upload.");
PP_EXPECT(harness, !save_required.show_cancel);
PP_EXPECT(harness, publish.title == "Publish document");
PP_EXPECT(harness, publish.message == "Would you like to upload to the public domain?");
PP_EXPECT(harness, publish.ok_caption == "Yes");
PP_EXPECT(harness, publish.cancel_caption == "No");
PP_EXPECT(harness, publish.show_cancel);
PP_EXPECT(harness, success.title == "Success");
PP_EXPECT(harness, success.message == "This document has been succesfully uploaded.");
PP_EXPECT(harness, !success.show_cancel);
}
void cloud_progress_dialog_plans_preserve_legacy_titles(pp::tests::Harness& harness)
{
const auto upload = pp::app::plan_cloud_upload_progress_dialog();
const auto bulk = pp::app::plan_cloud_bulk_upload_progress_dialog(4);
const auto download = pp::app::plan_cloud_download_progress_prompt();
PP_EXPECT(harness, upload.title == "Uploading");
PP_EXPECT(harness, upload.total == 0);
PP_EXPECT(harness, bulk.title == "Export Pano Image");
PP_EXPECT(harness, bulk.total == 4);
PP_EXPECT(harness, download.title == "Downloading");
PP_EXPECT(harness, download.message == "Download in progress");
PP_EXPECT(harness, download.show_cancel);
PP_EXPECT(harness, pp::app::format_cloud_download_progress_message(0.25F) == "Download in progress 25.00%");
}
void cloud_download_transfer_rejects_missing_url(pp::tests::Harness& harness)
{
const auto plan = pp::app::plan_cloud_download_transfer("", "D:/Paint/demo.ppi", true, true);
@@ -319,6 +354,8 @@ int main()
harness.run("cloud bulk upload runs without progress when ui unavailable", cloud_bulk_upload_runs_without_progress_when_ui_unavailable);
harness.run("cloud bulk upload keeps zero file progress explicit", cloud_bulk_upload_keeps_zero_file_progress_explicit);
harness.run("cloud bulk upload clamps progress total", cloud_bulk_upload_clamps_progress_total);
harness.run("cloud dialog plans preserve upload prompt metadata", cloud_dialog_plans_preserve_upload_prompt_metadata);
harness.run("cloud progress dialog plans preserve legacy titles", cloud_progress_dialog_plans_preserve_legacy_titles);
harness.run("cloud download transfer rejects missing url", cloud_download_transfer_rejects_missing_url);
harness.run("cloud download transfer rejects missing destination", cloud_download_transfer_rejects_missing_destination);
harness.run("cloud download transfer starts with progress and tls policy", cloud_download_transfer_starts_with_progress_and_tls_policy);

View File

@@ -3627,8 +3627,20 @@ int plan_cloud_upload(int argc, char** argv)
<< ",\"newDocument\":" << json_bool(args.new_document)
<< ",\"unsaved\":" << json_bool(args.unsaved)
<< "},\"decision\":\"" << cloud_upload_action_name(plan.action)
<< "\",\"saveBeforeUpload\":" << json_bool(plan.save_before_upload)
<< "}\n";
<< "\",\"saveBeforeUpload\":" << json_bool(plan.save_before_upload);
if (plan.action == pp::app::CloudUploadAction::show_save_required_warning
|| plan.action == pp::app::CloudUploadAction::prompt_publish) {
const auto prompt = plan.action == pp::app::CloudUploadAction::show_save_required_warning
? pp::app::plan_cloud_save_required_prompt()
: pp::app::plan_cloud_publish_prompt();
std::cout << ",\"prompt\":{\"title\":\"" << json_escape(prompt.title)
<< "\",\"message\":\"" << json_escape(prompt.message)
<< "\",\"okCaption\":\"" << json_escape(prompt.ok_caption)
<< "\",\"cancelCaption\":\"" << json_escape(prompt.cancel_caption)
<< "\",\"showCancel\":" << json_bool(prompt.show_cancel)
<< "}";
}
std::cout << "}\n";
return 0;
}
@@ -3716,7 +3728,16 @@ int plan_cloud_upload_all(int argc, char** argv)
<< "},\"plan\":{\"fileCount\":" << plan.file_count
<< ",\"progressTotal\":" << plan.progress_total
<< ",\"showProgress\":" << json_bool(plan.show_progress)
<< "}}\n";
<< "}";
if (plan.show_progress) {
const auto progress = pp::app::plan_cloud_bulk_upload_progress_dialog(plan.progress_total);
std::cout << ",\"progressDialog\":{\"title\":\"" << json_escape(progress.title)
<< "\",\"total\":" << progress.total
<< ",\"count\":" << progress.count
<< ",\"progressFraction\":" << progress.progress_fraction
<< "}";
}
std::cout << "}\n";
return 0;
}
@@ -3815,7 +3836,18 @@ int plan_cloud_transfer(int argc, char** argv)
<< ",\"disableTlsVerification\":" << json_bool(transfer.disable_tls_verification)
<< "},\"progress\":{\"notify\":" << json_bool(progress.notify)
<< ",\"fraction\":" << progress.fraction
<< "}}\n";
<< "}";
if (transfer.direction == pp::app::CloudTransferDirection::download
&& transfer.action == pp::app::CloudTransferAction::start_transfer) {
const auto prompt = pp::app::plan_cloud_download_progress_prompt();
std::cout << ",\"progressPrompt\":{\"title\":\"" << json_escape(prompt.title)
<< "\",\"message\":\"" << json_escape(prompt.message)
<< "\",\"showCancel\":" << json_bool(prompt.show_cancel)
<< ",\"formattedMessage\":\""
<< json_escape(pp::app::format_cloud_download_progress_message(progress.fraction))
<< "\"}";
}
std::cout << "}\n";
return 0;
}