From c698de1482830762c1d1d5c8cea2c3ee55632667 Mon Sep 17 00:00:00 2001 From: omigamedev Date: Thu, 4 Jun 2026 17:47:08 +0200 Subject: [PATCH] Route SonarPen tools action through platform services --- docs/modernization/build-inventory.md | 11 +++---- docs/modernization/debt.md | 4 +-- docs/modernization/roadmap.md | 13 +++++++-- src/app.h | 2 ++ src/app_events.cpp | 10 +++++++ src/app_layout.cpp | 25 +++++++++------- src/legacy_app_shell_services.cpp | 4 +-- src/platform_api/platform_services.h | 2 ++ .../legacy_platform_services.cpp | 16 ++++++++++ .../windows_platform_services.cpp | 9 ++++++ .../platform_api/platform_services_tests.cpp | 29 +++++++++++++++++++ 11 files changed, 102 insertions(+), 23 deletions(-) diff --git a/docs/modernization/build-inventory.md b/docs/modernization/build-inventory.md index d6f2948..7ba94f6 100644 --- a/docs/modernization/build-inventory.md +++ b/docs/modernization/build-inventory.md @@ -190,9 +190,9 @@ Known local toolchain state: menu routing, export-menu routing, main-toolbar commands, About menu commands, and direct Tools menu commands. It keeps those live paths on the `pp_app_core` contracts while legacy dialogs, pickers, cloud/share/export, - Tools, About, history, canvas-clear, and settings execution remain tracked by - `DEBT-0029`, `DEBT-0030`, `DEBT-0031`, `DEBT-0033`, `DEBT-0034`, and - `DEBT-0035`. + Tools, About, history, canvas-clear, settings, and platform SonarPen startup + execution remain tracked by `DEBT-0029`, `DEBT-0030`, `DEBT-0031`, + `DEBT-0033`, `DEBT-0034`, and `DEBT-0035`. - `src/legacy_app_preference_services.*` is the current app-shell bridge for options-menu preference execution. It keeps UI scale, viewport scale, RTL, VR mode, VR-controller, auto-timelapse, and canvas cursor-mode callbacks on @@ -554,8 +554,9 @@ Known local toolchain state: callbacks, recording cleanup, exported-image publishing, persistent storage flushing, document browse roots, native UI/window state saving, live asset/layout reload policy, diagnostic stacktrace/crash hooks, - prepared-file writable target selection, network TLS verification policy, - and prepared-file save/download handoff; PPBR and MP4 export dialogs consume + SonarPen availability/startup, prepared-file writable target selection, + network TLS verification policy, and prepared-file save/download handoff; PPBR + and MP4 export dialogs consume the same prepared-file policy at runtime instead of spelling mobile/Web branches locally, layer/frame collection export dialogs consume the work-directory collection policy before `pp_app_core` plans immediate diff --git a/docs/modernization/debt.md b/docs/modernization/debt.md index 2ab9566..788ad29 100644 --- a/docs/modernization/debt.md +++ b/docs/modernization/debt.md @@ -35,7 +35,7 @@ agent or engineer to remove them without reconstructing context from chat. | DEBT-0014 | Open | Modernization | `windows-clangcl-asan` now configures as a headless Ninja/clang-cl preset and uses the release MSVC runtime required by ASan, but local builds still fail because installed clang-cl 18.1.8 is paired with VS 2026-preview STL headers that require Clang 20 or newer | Sanitizer validation should be local and repeatable, but this machine's compiler/header pairing is incompatible | `cmake --fresh --preset windows-clangcl-asan`; `cmake --build --preset windows-clangcl-asan --target pp_foundation` | Install/use Clang 20+ with the VS 2026 STL, or point the preset at a compatible VS 2022 toolchain, then make `platform-build.ps1 -Presets windows-clangcl-asan` pass for the headless matrix | | DEBT-0015 | Open | Modernization | Cursor visibility requests now consume pure `pp_app_core` planning through `pano_cli plan-cursor-visibility`, `App::show_cursor`/`App::hide_cursor` dispatch through `PlatformServices` without platform guards, and Windows live execution uses injected `WindowsPlatformServices`, but macOS cursor execution still reaches the retained fallback adapter | Keep canvas cursor behavior stable while platform shells are extracted incrementally | `pp_app_core_document_platform_io_tests`; `pano_cli plan-cursor-visibility --visible`; `ctest --preset desktop-fast --build-config Debug` | Cursor visibility execution is owned by injected `pp_platform_*` services for every supported platform | | DEBT-0016 | Open | Modernization | Clipboard get/set requests now consume pure `pp_app_core` planning through `pano_cli plan-clipboard-read` and `pano_cli plan-clipboard-write`, and Windows live execution uses injected `WindowsPlatformServices`, but Apple/Android clipboard execution still reaches retained fallback adapter branches from `App::clipboard_get_text` and `App::clipboard_set_text` | Keep picker/color text clipboard behavior stable while platform shells are extracted incrementally | `pp_app_core_document_platform_io_tests`; `pano_cli plan-clipboard-write --text #ff00aa`; `ctest --preset desktop-fast --build-config Debug` | Clipboard execution is owned by injected `pp_platform_*` services for every supported platform | -| DEBT-0017 | Open | Modernization | Startup storage path preparation, `App::clipboard_get_text`, `App::clipboard_set_text`, `App::show_cursor`, `App::hide_cursor`, `App::showKeyboard`, `App::hideKeyboard`, `App::display_file`, `App::share_file`, native app/window close, UI-thread lifecycle hooks, render-context acquire/release/present hooks, render-target binding hooks, render platform hint hooks, render debug callback hooks, render-capture frame hooks, recording cleanup, live asset/layout reload policy, diagnostic stacktrace/crash hooks, per-frame platform hooks, `App::pick_image`, `App::pick_file`, the non-writer `App::pick_file_save`, `App::pick_dir`, prepared-file save/download handoff, work-directory document export collection policy, and app network TLS verification policy now call the SDK-free `pp::platform::PlatformServices` interface, and Windows injects `WindowsPlatformServices` from `src/platform_windows/windows_platform_services.*`; non-Windows live implementations still use `src/platform_legacy/legacy_platform_services.*`, a named fallback adapter that forwards to retained Apple/Android/Linux/Web bridge functions and retained no-op branches, including the retained Android TLS-verification bypass for current app curl helpers | Preserve behavior while moving platform execution behind a testable service boundary before platform shell implementations are injected | `pp_platform_api_tests`; `pp_app_core_document_export_tests`; `pp_app_core_document_platform_io_tests`; `ctest --preset desktop-fast --build-config Debug`; `powershell -ExecutionPolicy Bypass -File scripts\automation\package-smoke.ps1 -Preset windows-msvc-default -Configuration Debug` | Replace `src/platform_legacy/legacy_platform_services.*` with injected `pp_platform_*` service implementations owned by each non-Windows platform shell | +| DEBT-0017 | Open | Modernization | Startup storage path preparation, `App::clipboard_get_text`, `App::clipboard_set_text`, `App::show_cursor`, `App::hide_cursor`, `App::showKeyboard`, `App::hideKeyboard`, `App::display_file`, `App::share_file`, native app/window close, UI-thread lifecycle hooks, render-context acquire/release/present hooks, render-target binding hooks, render platform hint hooks, render debug callback hooks, render-capture frame hooks, recording cleanup, live asset/layout reload policy, diagnostic stacktrace/crash hooks, per-frame platform hooks, `App::pick_image`, `App::pick_file`, the non-writer `App::pick_file_save`, `App::pick_dir`, prepared-file save/download handoff, work-directory document export collection policy, app network TLS verification policy, and SonarPen availability/startup now call the SDK-free `pp::platform::PlatformServices` interface, and Windows injects `WindowsPlatformServices` from `src/platform_windows/windows_platform_services.*`; non-Windows live implementations still use `src/platform_legacy/legacy_platform_services.*`, a named fallback adapter that forwards to retained Apple/Android/Linux/Web bridge functions and retained no-op branches, including the retained Android TLS-verification bypass for current app curl helpers and retained iOS SonarPen bridge | Preserve behavior while moving platform execution behind a testable service boundary before platform shell implementations are injected | `pp_platform_api_tests`; `pp_app_core_document_export_tests`; `pp_app_core_document_platform_io_tests`; `ctest --preset desktop-fast --build-config Debug`; `powershell -ExecutionPolicy Bypass -File scripts\automation\package-smoke.ps1 -Preset windows-msvc-default -Configuration Debug` | Replace `src/platform_legacy/legacy_platform_services.*` with injected `pp_platform_*` service implementations owned by each non-Windows platform shell | | DEBT-0019 | Open | Modernization | Unreferenced-parameter warnings are muted globally through `pp_project_warnings` with MSVC `/wd4100` and Clang/GCC `-Wno-unused-parameter` | Legacy callbacks, virtual hooks, serializer methods, and platform/API compatibility functions carry many intentionally unused parameters during the component split; muting this keeps stricter warning builds focused on higher-signal migration issues | `cmake --build --preset windows-msvc-default --config Debug --target PanoPainter`; `ctest --preset desktop-fast --build-config Debug`; `cmake --build --preset linux-clang --target pp_foundation` | Remove `/wd4100` and `-Wno-unused-parameter`, mark intentionally unused parameters with names/comments or `[[maybe_unused]]`, and make the Windows app plus headless Clang/GCC tests pass without unreferenced-parameter warnings | | DEBT-0020 | Open | Modernization | Document resize dialog state, selected-resolution planning, and execution dispatch now consume pure `pp_app_core` through `NodeDialogResize`, `App::dialog_resize`, `pano_cli plan-document-resize`, and the `DocumentResizeServices` boundary, and live resize shares `src/legacy_document_canvas_services.*` with canvas clear commands, but the shared live bridge still calls legacy `Canvas::resize`, updates the legacy app title, and clears legacy `ActionManager` history through the history bridge | Preserve existing layer/frame GPU resize behavior while the document model and canvas execution boundary are extracted incrementally | `pp_app_core_document_resize_tests`; `pano_cli plan-document-resize --current-resolution 2048 --selected-resolution-index 4`; `ctest --preset desktop-fast --build-config Debug` | Document resize execution is owned by injected document/app services with no legacy resize adapter, title shim, or direct `ActionManager` history clearing | | DEBT-0021 | Open | Modernization | Layer rename planning/execution dispatch and layer panel operation planning/execution dispatch now consume pure `pp_app_core` through `App::dialog_layer_rename`, `App::init_sidebar` layer callbacks, `pano_cli plan-layer-rename`, `pano_cli plan-layer-operation`, `DocumentLayerRenameServices`, and `DocumentLayerOperationServices`, and the live execution adapters are centralized in `src/legacy_document_layer_services.*`, but that shared bridge still mutates legacy `Canvas` layer state, `NodeLayer`/`NodePanelLayer`, and `ActionManager` undo entries | Preserve existing UI/canvas behavior while document layer commands and undo history are extracted incrementally | `pp_app_core_document_layer_tests`; `pano_cli plan-layer-rename --old-name Base --new-name Paint`; `pano_cli plan-layer-operation --kind add --layer-count 2 --index 1 --name Paint`; `ctest --preset desktop-fast --build-config Debug` | Layer command execution is owned by the document/app command boundary with legacy `Canvas`/UI nodes acting only as adapters or removed entirely | @@ -50,7 +50,7 @@ agent or engineer to remove them without reconstructing context from chat. | DEBT-0030 | Open | Modernization | File export menu action planning and execution dispatch now consume pure `pp_app_core` through the File menu, `pano_cli plan-export-menu`, and the `DocumentExportMenuServices` boundary, and live execution is centralized in `src/legacy_app_shell_services.*`, but the bridge still opens legacy export dialogs and then reaches legacy canvas/render/video export code | Preserve current export menu behavior while export command execution moves toward document/app/renderer/video services | `pp_app_core_document_export_tests`; `pano_cli plan-export-menu --kind png`; `pano_cli plan-export-menu --kind animation-mp4 --demo`; `pano_cli plan-export-menu --kind layers --no-canvas`; `ctest --preset desktop-fast --build-config Debug` | Export menu routing, license gating, target creation, image/layer/cube/depth/animation/timelapse execution, and error reporting are owned by injected document/app/renderer/video services with File-menu callbacks acting only as UI adapters and no legacy export adapter | | DEBT-0031 | Open | Modernization | Top-level File menu command planning and execution dispatch now consume pure `pp_app_core` through `App::init_menu_file`, `pano_cli plan-file-menu`, and the `FileMenuServices` boundary, and live execution is centralized in `src/legacy_app_shell_services.*`, but the bridge still invokes legacy dialogs, platform pickers, cloud code, share code, and canvas import/export paths directly | Preserve File menu behavior while app workflows move toward app/document/platform command services | `pp_app_core_file_menu_tests`; `pano_cli plan-file-menu --command save-as`; `pano_cli plan-file-menu --command import`; `pano_cli plan-file-menu --command cloud-upload`; `ctest --preset desktop-fast --build-config Debug` | File menu routing, picker dispatch, save/share/cloud/resize/export execution, and image/project import execution are owned by injected app/document/platform services with `App::init_menu_file` acting only as a UI adapter and no legacy File menu adapter | | DEBT-0032 | Open | Modernization | Layer menu command planning and execution dispatch now consume pure `pp_app_core` through `App::init_menu_layer`, `pano_cli plan-layer-menu`, and the `DocumentLayerMenuServices` boundary; Layer menu clear reuses the `DocumentCanvasClearServices` executor; and Layer menu rename/clear/merge now share `src/legacy_document_layer_services.*`, but the bridge still calls the legacy rename dialog path, `NodePanelLayer::merge`, and reads `Canvas::I` animation/layer state directly | Preserve existing Layer menu behavior while layer commands move toward document/app services | `pp_app_core_document_layer_tests`; `pano_cli plan-layer-menu --command clear --current-index 1 --current-name Paint`; `pano_cli plan-layer-menu --command merge --current-index 2 --lower-name Paint`; `pano_cli plan-layer-merge --layer-count 3 --from-index 2 --to-index 1`; `pano_cli plan-layer-merge --layer-count 3 --from-index 2 --to-index 1 --animation-duration 3`; `pano_cli plan-layer-menu --command rename --no-current-layer`; `ctest --preset desktop-fast --build-config Debug` | Layer rename, merge-down execution, animation gating, and selected-layer state are owned by injected document/app services with Layer-menu callbacks acting only as UI adapters and no legacy Layer menu adapter | -| DEBT-0033 | Open | Modernization | Tools menu planning and direct command execution dispatch now consume pure `pp_app_core` through `App::init_menu_tools`, `pano_cli plan-tools-menu`, `pano_cli plan-tools-panel`, and the `ToolsMenuServices` boundary, and direct command execution is centralized in `src/legacy_app_shell_services.*`, but live adapters still construct legacy `NodePanelFloating` panels, mutate legacy panel nodes, clear `CanvasModeGrid`, reset `NodeCanvas` camera state, open legacy shortcuts UI, and call the iOS SonarPen bridge directly | Preserve current Tools menu behavior while UI shell actions move toward app/UI/platform services | `pp_app_core_tools_menu_tests`; `pano_cli plan-tools-menu --command shortcuts`; `pano_cli plan-tools-panel --panel layers`; `pano_cli plan-tools-panel --panel animation --already-visible`; `ctest --preset desktop-fast --build-config Debug` | Tools panel creation, submenu routing, grid clear, camera reset, shortcuts dialog, and SonarPen dispatch are owned by injected app/UI/platform services with `App::init_menu_tools` acting only as a UI adapter and no legacy Tools adapter | +| DEBT-0033 | Open | Modernization | Tools menu planning and direct command execution dispatch now consume pure `pp_app_core` through `App::init_menu_tools`, `pano_cli plan-tools-menu`, `pano_cli plan-tools-panel`, and the `ToolsMenuServices` boundary, and direct command execution is centralized in `src/legacy_app_shell_services.*`; SonarPen availability/startup now routes through `PlatformServices`, but live adapters still construct legacy `NodePanelFloating` panels, mutate legacy panel nodes, clear `CanvasModeGrid`, reset `NodeCanvas` camera state, open legacy shortcuts UI, and rely on the legacy platform adapter for the retained iOS SonarPen bridge | Preserve current Tools menu behavior while UI shell actions move toward app/UI/platform services | `pp_app_core_tools_menu_tests`; `pp_platform_api_tests`; `pano_cli plan-tools-menu --command shortcuts`; `pano_cli plan-tools-panel --panel layers`; `pano_cli plan-tools-panel --panel animation --already-visible`; `ctest --preset desktop-fast --build-config Debug` | Tools panel creation, submenu routing, grid clear, camera reset, shortcuts dialog, and SonarPen dispatch are owned by injected app/UI/platform services with `App::init_menu_tools` acting only as a UI adapter and no legacy Tools adapter | | DEBT-0034 | Open | Modernization | About menu command planning and execution dispatch now consume pure `pp_app_core` through `App::init_menu_about`, `pano_cli plan-about-menu`, and the `AboutMenuServices` boundary, and live execution is centralized in `src/legacy_app_shell_services.*`, but the bridge still opens legacy About/manual/what's-new dialogs, invokes the injected crash hook, and runs the legacy Canvas stroke performance test directly | Preserve About menu behavior while dialogs and diagnostics move toward app/UI/platform services | `pp_app_core_about_menu_tests`; `pano_cli plan-about-menu --command news --version-major 2 --version-minor 5 --version-fix 7`; `pano_cli plan-about-menu --command performance --no-canvas`; `ctest --preset desktop-fast --build-config Debug` | About/manual/what's-new dialog dispatch, crash-test dispatch, and performance-test execution are owned by injected app/UI/platform services with `App::init_menu_about` acting only as a UI adapter and no legacy About 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::render_device_features` as the backend conversion point. `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. Actual live stroke rasterization, dual-brush compositing, pattern feedback math, thumbnail layer compositing, and brush-preview compositing 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 | diff --git a/docs/modernization/roadmap.md b/docs/modernization/roadmap.md index 0806064..3cdb47c 100644 --- a/docs/modernization/roadmap.md +++ b/docs/modernization/roadmap.md @@ -614,6 +614,10 @@ dispatch through `ToolsMenuServices` in the shared app-shell bridge before the legacy UI/panel/canvas/platform adapters continue execution. The live animation panel route now also checks animation panel visibility and applies animation panel layout state instead of using the grid panel by mistake. +The live SonarPen menu action now asks the active `PlatformServices` instance +for availability and startup, removing the local iOS branch from the Tools menu +and shared Tools executor while preserving the retained iOS bridge in the +legacy platform adapter. Options-menu preference callbacks now dispatch UI scale, viewport scale, RTL, VR mode, VR-controller, auto-timelapse, and cursor-mode side effects through `AppPreferenceServices` in `src/legacy_app_preference_services.*` before @@ -632,8 +636,8 @@ virtual-keyboard visibility, UI-thread lifecycle hooks, render-context acquire/release/present hooks, render-target binding hooks, render-capture frame hooks, render platform hint hooks, render debug callback hooks, external file display, file sharing, recording file cleanup, live asset/layout reload -policy, diagnostic stacktrace/crash hooks, image/file/save-file pickers, and -directory pickers. +policy, diagnostic stacktrace/crash hooks, SonarPen availability/startup, +image/file/save-file pickers, and directory pickers. Windows installs an injected `WindowsPlatformServices` implementation from `src/platform_windows/windows_platform_services.*` in `pp_platform_windows`; other platforms still route through the debt-tracked legacy fallback adapter @@ -660,6 +664,10 @@ App-owned curl helpers for download, upload, and license checks now ask local Android branches from those helpers while preserving Android's existing TLS-verification bypass in the legacy adapter until a network/platform service owns cloud transport. +The Tools menu SonarPen entry now asks `PlatformServices` whether SonarPen is +available and dispatches startup through the same service, preserving the +current iOS Objective-C bridge in the legacy adapter while removing iOS branches +from `App::init_menu_tools` and `LegacyToolsMenuServices`. Canvas image export publishing and explicit persistent-storage flushes now dispatch through `PlatformServices` too, preserving iOS photo-library export publication and WebGL filesystem sync behavior in the legacy adapter while @@ -1720,6 +1728,7 @@ Results: native UI/window state save dispatch, prepared-file writable target dispatch, prepared-file export-dialog policy dispatch, work-directory document export collection policy dispatch, network TLS verification policy dispatch, + SonarPen availability/startup dispatch, live asset/layout reload policy dispatch, diagnostic hook dispatch, per-frame platform hook dispatch, picker callback dispatch, and prepared-file save/download callback dispatch. The live Windows diff --git a/src/app.h b/src/app.h index 7d75717..494d668 100644 --- a/src/app.h +++ b/src/app.h @@ -187,6 +187,8 @@ public: [[nodiscard]] bool uses_prepared_file_writes() const; [[nodiscard]] bool uses_work_directory_document_export_collections() const; [[nodiscard]] bool disables_network_tls_verification() const; + [[nodiscard]] bool platform_supports_sonarpen() const; + void start_platform_sonarpen(); void pick_dir(std::function callback); void display_file(std::string path); void share_file(std::string path); diff --git a/src/app_events.cpp b/src/app_events.cpp index c8aa4c6..0bc9f53 100644 --- a/src/app_events.cpp +++ b/src/app_events.cpp @@ -196,6 +196,16 @@ bool App::disables_network_tls_verification() const return active_platform_services().disables_network_tls_verification(); } +bool App::platform_supports_sonarpen() const +{ + return active_platform_services().supports_sonarpen(); +} + +void App::start_platform_sonarpen() +{ + active_platform_services().start_sonarpen(); +} + void App::pick_dir(std::function callback) { redraw = true; diff --git a/src/app_layout.cpp b/src/app_layout.cpp index 18c3742..15dc218 100644 --- a/src/app_layout.cpp +++ b/src/app_layout.cpp @@ -1265,17 +1265,20 @@ void App::init_menu_tools() }; */ -#if __IOS__ - popup_exp->find("sonarpen")->on_click = [this, popup_exp](Node*) { - const auto plan = pp::app::plan_tools_menu_command(pp::app::ToolsMenuCommand::sonarpen, true); - execute_tools_menu_plan(*this, plan); - if (plan.closes_root_popup) - { - popup_exp->mouse_release(); - popup_exp->destroy(); - } - }; -#endif + if (platform_supports_sonarpen()) + { + popup_exp->find("sonarpen")->on_click = [this, popup_exp](Node*) { + const auto plan = pp::app::plan_tools_menu_command( + pp::app::ToolsMenuCommand::sonarpen, + platform_supports_sonarpen()); + execute_tools_menu_plan(*this, plan); + if (plan.closes_root_popup) + { + popup_exp->mouse_release(); + popup_exp->destroy(); + } + }; + } }; } } diff --git a/src/legacy_app_shell_services.cpp b/src/legacy_app_shell_services.cpp index bb9d60c..287c6a9 100644 --- a/src/legacy_app_shell_services.cpp +++ b/src/legacy_app_shell_services.cpp @@ -315,9 +315,7 @@ public: void start_sonarpen() override { -#if __IOS__ - [app_.ios_app sonarpen_start]; -#endif + app_.start_platform_sonarpen(); } private: diff --git a/src/platform_api/platform_services.h b/src/platform_api/platform_services.h index 41d4bc2..1ae6529 100644 --- a/src/platform_api/platform_services.h +++ b/src/platform_api/platform_services.h @@ -66,6 +66,8 @@ public: [[nodiscard]] virtual bool uses_prepared_file_writes() = 0; [[nodiscard]] virtual bool uses_work_directory_document_export_collections() = 0; [[nodiscard]] virtual bool disables_network_tls_verification() = 0; + [[nodiscard]] virtual bool supports_sonarpen() = 0; + virtual void start_sonarpen() = 0; [[nodiscard]] virtual PreparedFileTarget prepare_writable_file( std::string_view type, std::string_view default_name, diff --git a/src/platform_legacy/legacy_platform_services.cpp b/src/platform_legacy/legacy_platform_services.cpp index 3682846..97de38e 100644 --- a/src/platform_legacy/legacy_platform_services.cpp +++ b/src/platform_legacy/legacy_platform_services.cpp @@ -458,6 +458,22 @@ public: #endif } + [[nodiscard]] bool supports_sonarpen() override + { +#if __IOS__ + return true; +#else + return false; +#endif + } + + void start_sonarpen() override + { +#if __IOS__ + [App::I->ios_app sonarpen_start]; +#endif + } + [[nodiscard]] pp::platform::PreparedFileTarget prepare_writable_file( std::string_view type, std::string_view default_name, diff --git a/src/platform_windows/windows_platform_services.cpp b/src/platform_windows/windows_platform_services.cpp index 0c8ce5c..dd280ad 100644 --- a/src/platform_windows/windows_platform_services.cpp +++ b/src/platform_windows/windows_platform_services.cpp @@ -463,6 +463,15 @@ public: return false; } + [[nodiscard]] bool supports_sonarpen() override + { + return false; + } + + void start_sonarpen() override + { + } + [[nodiscard]] pp::platform::PreparedFileTarget prepare_writable_file( std::string_view type, std::string_view default_name, diff --git a/tests/platform_api/platform_services_tests.cpp b/tests/platform_api/platform_services_tests.cpp index 2113818..04acd36 100644 --- a/tests/platform_api/platform_services_tests.cpp +++ b/tests/platform_api/platform_services_tests.cpp @@ -228,6 +228,17 @@ public: return network_tls_verification_disabled; } + [[nodiscard]] bool supports_sonarpen() override + { + ++sonarpen_support_checks; + return sonarpen_supported; + } + + void start_sonarpen() override + { + ++sonarpen_starts; + } + [[nodiscard]] pp::platform::PreparedFileTarget prepare_writable_file( std::string_view type, std::string_view default_name, @@ -290,6 +301,8 @@ public: int prepared_file_write_policy_checks = 0; int document_export_collection_policy_checks = 0; int network_tls_policy_checks = 0; + int sonarpen_support_checks = 0; + int sonarpen_starts = 0; int prepare_writable_file_requests = 0; int save_prepared_file_requests = 0; bool cursor_visible = false; @@ -298,6 +311,7 @@ public: bool prepared_file_writes = true; bool work_directory_document_export_collections = false; bool network_tls_verification_disabled = false; + bool sonarpen_supported = false; bool deletes_recorded_files = true; bool live_asset_reloading = true; float last_platform_delta = 0.0f; @@ -635,6 +649,20 @@ void platform_services_dispatch_network_tls_policy(pp::tests::Harness& harness) PP_EXPECT(harness, fake.network_tls_policy_checks == 2); } +void platform_services_dispatch_sonarpen_policy_and_start(pp::tests::Harness& harness) +{ + FakePlatformServices fake("unused"); + pp::platform::PlatformServices& services = fake; + + PP_EXPECT(harness, !services.supports_sonarpen()); + fake.sonarpen_supported = true; + PP_EXPECT(harness, services.supports_sonarpen()); + services.start_sonarpen(); + + PP_EXPECT(harness, fake.sonarpen_support_checks == 2); + PP_EXPECT(harness, fake.sonarpen_starts == 1); +} + } int main() @@ -662,5 +690,6 @@ int main() "platform services dispatch document export collection policy", platform_services_dispatch_document_export_collection_policy); harness.run("platform services dispatch network tls policy", platform_services_dispatch_network_tls_policy); + harness.run("platform services dispatch sonarpen policy and start", platform_services_dispatch_sonarpen_policy_and_start); return harness.finish(); }