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 renderer API to OpenGL token mapping and command-planning contracts used by
the OpenGL parity work. the OpenGL parity work.
- `pano_cli plan-cloud-upload` exposes `pp_app_core` cloud upload availability, - `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 the live cloud upload command consumes the same start contract before
reaching legacy UI, canvas save, and network upload execution. reaching legacy UI, canvas save, and network upload execution.
- `pano_cli plan-cloud-upload-all` exposes bulk cloud upload file-count, - `pano_cli plan-cloud-upload-all` exposes bulk cloud upload file-count,
progress UI availability, and progress-total clamping as JSON; the live progress UI availability, progress-total clamping, and progress dialog
upload-all command consumes the same contract before reaching legacy asset metadata as JSON; the live upload-all command consumes the same contract
file listing, OpenGL context guard, progress UI, and network upload before reaching legacy asset file listing, OpenGL context guard, progress UI,
and network upload
execution. execution.
- `pano_cli plan-cloud-browse` exposes `pp_app_core` cloud browse availability - `pano_cli plan-cloud-browse` exposes `pp_app_core` cloud browse availability
and selected-file download planning as JSON; the live cloud browse command 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 live paths on the `pp_app_core` `CloudServices` contract while the app-owned
curl upload/download/license helpers now ask `PlatformServices` for TLS curl upload/download/license helpers now ask `PlatformServices` for TLS
verification policy and retained dialog/network curl sites use the shared 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, network upload/download helper ownership, OpenGL context guarding,
`NodeDialogCloud`, project open, layer refresh, and action-history reset `NodeDialogCloud`, project open, layer refresh, and action-history reset
remain tracked by `DEBT-0038`. 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 progress-callback, and zero/overrun progress cases for automation. CURL
ownership, response/error handling, progress UI, cloud dialog/document ownership, response/error handling, progress UI, cloud dialog/document
execution, and injected network service work remain open under DEBT-0038. 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 - 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 dialog metadata now lives in tested `pp_app_core` planning consumed by
`App::show_progress`, `App::message_box`, `App::input_box`, and `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-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-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-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-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-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 | | 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. before retained CURL setup.
- Android arm64 headless `pp_app_core`, `pano_cli`, and - Android arm64 headless `pp_app_core`, `pano_cli`, and
`pp_app_core_document_cloud_tests` built after the cloud transfer slice. `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 - `PanoPainter`, `pp_app_core_document_cloud_tests`, and `pano_cli` built after
live cloud upload, bulk upload, and browse/download execution moved behind live cloud upload, bulk upload, and browse/download execution moved behind
the `CloudServices` boundary and `src/legacy_cloud_services.*`. the `CloudServices` boundary and `src/legacy_cloud_services.*`.

View File

@@ -1,7 +1,9 @@
#pragma once #pragma once
#include "app_core/app_dialog.h"
#include "foundation/result.h" #include "foundation/result.h"
#include <cstdio>
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
#include <limits> #include <limits>
@@ -66,6 +68,61 @@ struct CloudTransferProgressPlan {
float fraction = 0.0F; 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 { class CloudServices {
public: public:
virtual ~CloudServices() = default; virtual ~CloudServices() = default;

View File

@@ -12,6 +12,20 @@
namespace pp::panopainter { namespace pp::panopainter {
namespace { 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 { class LegacyCloudServices final : public pp::app::CloudServices {
public: public:
explicit LegacyCloudServices(App& app) noexcept explicit LegacyCloudServices(App& app) noexcept
@@ -21,7 +35,8 @@ public:
void show_save_required_warning() override 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 void prompt_publish(bool save_before_upload) override
@@ -35,19 +50,20 @@ public:
Canvas::I->project_save_thread(app->doc_path, true); 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) { app->upload(app->doc_path, app->doc_filename, [pb](float p) {
pb->set_progress(p); pb->set_progress(p);
}); });
pb->destroy(); 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?"); const auto prompt_plan = pp::app::plan_cloud_publish_prompt();
m->btn_ok->m_text->set_text("Yes"); auto m = app_.message_box(prompt_plan.title, prompt_plan.message, prompt_plan.show_cancel);
m->btn_cancel->m_text->set_text("No");
m->btn_ok->on_click = [m, upload_thread](Node*) { m->btn_ok->on_click = [m, upload_thread](Node*) {
std::thread(upload_thread).detach(); std::thread(upload_thread).detach();
m->destroy(); m->destroy();
@@ -61,7 +77,8 @@ public:
{ {
bulk_progress_.reset(); bulk_progress_.reset();
if (show_progress) { 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(); BT_SetTerminate();
auto* m = app->layout[app->main_id]->add_child<NodeMessageBox>(); auto* m = app->layout[app->main_id]->add_child<NodeMessageBox>();
m->m_title->set_text("Downloading"); apply_cloud_message_box_plan(*m, pp::app::plan_cloud_download_progress_prompt());
m->m_message->set_text("Download in progress");
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) { app->download(url, request.selected_path, [m](float p) {
static char progress[256]; const auto progress = pp::app::format_cloud_download_progress_message(p);
sprintf(progress, "Download in progress %.2f%%", p * 100.f); m->m_message->set_text(progress.c_str());
m->m_message->set_text(progress);
}); });
const auto reset_status = execute_legacy_canvas_camera_reset(*app); 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) COMMAND pano_cli plan-cloud-upload)
set_tests_properties(pano_cli_plan_cloud_upload_clean_smoke PROPERTIES set_tests_properties(pano_cli_plan_cloud_upload_clean_smoke PROPERTIES
LABELS "app;integration;desktop-fast" 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 add_test(NAME pano_cli_plan_cloud_upload_unsaved_smoke
COMMAND pano_cli plan-cloud-upload --unsaved) COMMAND pano_cli plan-cloud-upload --unsaved)
@@ -915,7 +915,7 @@ if(TARGET pano_cli)
COMMAND pano_cli plan-cloud-upload --new-document --unsaved) COMMAND pano_cli plan-cloud-upload --new-document --unsaved)
set_tests_properties(pano_cli_plan_cloud_upload_new_document_smoke PROPERTIES set_tests_properties(pano_cli_plan_cloud_upload_new_document_smoke PROPERTIES
LABELS "app;integration;desktop-fast;fuzz" 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 add_test(NAME pano_cli_plan_cloud_upload_no_canvas_smoke
COMMAND pano_cli plan-cloud-upload --no-canvas --new-document --unsaved) 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) COMMAND pano_cli plan-cloud-upload-all --file-count 3)
set_tests_properties(pano_cli_plan_cloud_upload_all_progress_smoke PROPERTIES set_tests_properties(pano_cli_plan_cloud_upload_all_progress_smoke PROPERTIES
LABELS "app;integration;desktop-fast" 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 add_test(NAME pano_cli_plan_cloud_upload_all_headless_smoke
COMMAND pano_cli plan-cloud-upload-all --file-count 3 --no-progress-ui) 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) 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 set_tests_properties(pano_cli_plan_cloud_transfer_download_smoke PROPERTIES
LABELS "app;integration;desktop-fast" 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 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) 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); 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) 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); 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 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 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 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 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 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); 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) << ",\"newDocument\":" << json_bool(args.new_document)
<< ",\"unsaved\":" << json_bool(args.unsaved) << ",\"unsaved\":" << json_bool(args.unsaved)
<< "},\"decision\":\"" << cloud_upload_action_name(plan.action) << "},\"decision\":\"" << cloud_upload_action_name(plan.action)
<< "\",\"saveBeforeUpload\":" << json_bool(plan.save_before_upload) << "\",\"saveBeforeUpload\":" << json_bool(plan.save_before_upload);
<< "}\n"; 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; return 0;
} }
@@ -3716,7 +3728,16 @@ int plan_cloud_upload_all(int argc, char** argv)
<< "},\"plan\":{\"fileCount\":" << plan.file_count << "},\"plan\":{\"fileCount\":" << plan.file_count
<< ",\"progressTotal\":" << plan.progress_total << ",\"progressTotal\":" << plan.progress_total
<< ",\"showProgress\":" << json_bool(plan.show_progress) << ",\"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; return 0;
} }
@@ -3815,7 +3836,18 @@ int plan_cloud_transfer(int argc, char** argv)
<< ",\"disableTlsVerification\":" << json_bool(transfer.disable_tls_verification) << ",\"disableTlsVerification\":" << json_bool(transfer.disable_tls_verification)
<< "},\"progress\":{\"notify\":" << json_bool(progress.notify) << "},\"progress\":{\"notify\":" << json_bool(progress.notify)
<< ",\"fraction\":" << progress.fraction << ",\"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; return 0;
} }