Route VR mode through app preferences

This commit is contained in:
2026-06-04 14:22:39 +02:00
parent f8243566c4
commit 884a6d4940
8 changed files with 79 additions and 23 deletions

View File

@@ -169,10 +169,10 @@ Known local toolchain state:
`DEBT-0035`. `DEBT-0035`.
- `src/legacy_app_preference_services.*` is the current app-shell bridge for - `src/legacy_app_preference_services.*` is the current app-shell bridge for
options-menu preference execution. It keeps UI scale, viewport scale, RTL, options-menu preference execution. It keeps UI scale, viewport scale, RTL,
VR-controller, auto-timelapse, and canvas cursor-mode callbacks on the VR mode, VR-controller, auto-timelapse, and canvas cursor-mode callbacks on
`pp_app_core` `AppPreferenceServices` contract while retained settings the `pp_app_core` `AppPreferenceServices` contract while retained settings
persistence, recording lifecycle, and legacy canvas/UI execution remain persistence, VR start/stop, recording lifecycle, and legacy canvas/UI
tracked by `DEBT-0045`. execution remain tracked by `DEBT-0045`.
- `src/legacy_canvas_tool_services.*` is the current app-shell bridge for - `src/legacy_canvas_tool_services.*` is the current app-shell bridge for
canvas toolbar tool selection, NodeCanvas stylus/input mode switching, and canvas toolbar tool selection, NodeCanvas stylus/input mode switching, and
canvas hotkey/touch execution. It keeps those live paths on the `pp_app_core` canvas hotkey/touch execution. It keeps those live paths on the `pp_app_core`
@@ -584,8 +584,9 @@ Known local toolchain state:
planning before platform clipboard callbacks. planning before platform clipboard callbacks.
- `pp_app_core_app_preferences_tests` covers UI scale/font-scale planning, - `pp_app_core_app_preferences_tests` covers UI scale/font-scale planning,
scale-option selection, viewport scale planning, RTL direction planning, scale-option selection, viewport scale planning, RTL direction planning,
timelapse start/stop/no-op decisions, simple stored preferences, and timelapse start/stop/no-op decisions, VR mode success/failure dispatch,
`AppPreferenceServices` execution dispatch for options-menu side effects. simple stored preferences, and `AppPreferenceServices` execution dispatch for
options-menu side effects.
- `pp_platform_api_tests` covers service dispatch for clipboard read/write, - `pp_platform_api_tests` covers service dispatch for clipboard read/write,
empty clipboard writes, cursor visibility, virtual-keyboard visibility, empty clipboard writes, cursor visibility, virtual-keyboard visibility,
external file display, file sharing, and picker callbacks without platform external file display, file sharing, and picker callbacks without platform

View File

@@ -62,7 +62,7 @@ agent or engineer to remove them without reconstructing context from chat.
| DEBT-0042 | Open | Modernization | Accepted Save As and Save Version planning/execution dispatch now consumes pure `pp_app_core` through `App::dialog_save`, `App::dialog_save_ver`, `pano_cli plan-document-file`, `pano_cli plan-document-version`, `DocumentFileSaveServices`, `DocumentVersionSaveServices`, and `src/legacy_document_session_services.*`, but the bridge still opens legacy overwrite prompts, calls legacy `Canvas::project_save`, mutates app document name/path/directory fields, marks version saves dirty before saving, updates the title, and handles keyboard/dialog cleanup directly | Preserve current Save As and Save Version behavior while document persistence moves toward app/document/storage/UI services | `pp_app_core_document_session_tests`; `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`; `pano_cli simulate-app-session --save-intent save-as`; `pano_cli simulate-app-session --save-intent save-version`; `ctest --preset desktop-fast --build-config Debug` | Save As overwrite prompting, project-save execution, app document metadata updates, title updates, version-save dirty-state handling, and keyboard/dialog cleanup are owned by injected app/document/storage/UI services with `App::dialog_save` and `App::dialog_save_ver` acting only as UI adapters | | DEBT-0042 | Open | Modernization | Accepted Save As and Save Version planning/execution dispatch now consumes pure `pp_app_core` through `App::dialog_save`, `App::dialog_save_ver`, `pano_cli plan-document-file`, `pano_cli plan-document-version`, `DocumentFileSaveServices`, `DocumentVersionSaveServices`, and `src/legacy_document_session_services.*`, but the bridge still opens legacy overwrite prompts, calls legacy `Canvas::project_save`, mutates app document name/path/directory fields, marks version saves dirty before saving, updates the title, and handles keyboard/dialog cleanup directly | Preserve current Save As and Save Version behavior while document persistence moves toward app/document/storage/UI services | `pp_app_core_document_session_tests`; `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`; `pano_cli simulate-app-session --save-intent save-as`; `pano_cli simulate-app-session --save-intent save-version`; `ctest --preset desktop-fast --build-config Debug` | Save As overwrite prompting, project-save execution, app document metadata updates, title updates, version-save dirty-state handling, and keyboard/dialog cleanup are owned by injected app/document/storage/UI services with `App::dialog_save` and `App::dialog_save_ver` acting only as UI adapters |
| DEBT-0043 | Open | Modernization | Equirectangular, layer, animation-frame, depth, and cube-face export planning/execution dispatch now consumes pure `pp_app_core` through `App::dialog_export`, `App::dialog_export_layers`, `App::dialog_export_anim_frames`, `App::dialog_export_depth`, `App::dialog_export_cube_faces`, `pano_cli plan-export-*`, `DocumentExportServices`, and `src/legacy_document_export_services.*`, but the bridge still calls legacy `Canvas` export methods, owns platform-specific export success messages, creates export directories, handles picker-selected stems, and performs Web prepared-file handoff directly | Preserve current image/collection/depth/cube export behavior while export execution moves toward document/renderer/platform/storage services | `pp_app_core_document_export_tests`; `pano_cli plan-export-start --requires-license --demo`; `pano_cli plan-export-menu --kind layers`; `pano_cli plan-export-target --kind collection --work-dir D:/Paint --doc-name demo --suffix _layers`; `pano_cli simulate-document-export`; `ctest --preset desktop-fast --build-config Debug` | File, collection, stem, depth, and cube export execution, export-directory creation, platform success reporting, Web file handoff, and legacy canvas export calls are owned by injected document/renderer/platform/storage services with export dialogs acting only as UI adapters | | DEBT-0043 | Open | Modernization | Equirectangular, layer, animation-frame, depth, and cube-face export planning/execution dispatch now consumes pure `pp_app_core` through `App::dialog_export`, `App::dialog_export_layers`, `App::dialog_export_anim_frames`, `App::dialog_export_depth`, `App::dialog_export_cube_faces`, `pano_cli plan-export-*`, `DocumentExportServices`, and `src/legacy_document_export_services.*`, but the bridge still calls legacy `Canvas` export methods, owns platform-specific export success messages, creates export directories, handles picker-selected stems, and performs Web prepared-file handoff directly | Preserve current image/collection/depth/cube export behavior while export execution moves toward document/renderer/platform/storage services | `pp_app_core_document_export_tests`; `pano_cli plan-export-start --requires-license --demo`; `pano_cli plan-export-menu --kind layers`; `pano_cli plan-export-target --kind collection --work-dir D:/Paint --doc-name demo --suffix _layers`; `pano_cli simulate-document-export`; `ctest --preset desktop-fast --build-config Debug` | File, collection, stem, depth, and cube export execution, export-directory creation, platform success reporting, Web file handoff, and legacy canvas export calls are owned by injected document/renderer/platform/storage services with export dialogs acting only as UI adapters |
| DEBT-0044 | Open | Modernization | Timelapse and animation MP4 export execution dispatch now consumes pure `pp_app_core` through `App::dialog_timelapse_export`, `App::dialog_export_mp4`, `pano_cli plan-export-menu`, `pano_cli plan-export-target --kind name`, `DocumentVideoExportServices`, and `src/legacy_document_export_services.*`, but the bridge still launches legacy desktop timelapse worker threads, calls `App::rec_export`, calls `Canvas::export_anim_mp4`, owns mobile/Web save callbacks, and emits success messages directly | Preserve current MP4/timelapse export behavior while video export moves toward app/document/renderer/video/platform/storage services | `pp_app_core_document_export_tests`; `pano_cli plan-export-menu --kind animation-mp4`; `pano_cli plan-export-menu --kind timelapse`; `pano_cli plan-export-target --kind name --doc-name demo --suffix -animation`; `pano_cli plan-export-target --kind name --doc-name demo --suffix -timelapse`; `ctest --preset desktop-fast --build-config Debug` | Timelapse and animation MP4 execution, desktop worker threading, frame readback/video encoding handoff, mobile/Web save callbacks, and success reporting are owned by injected app/document/renderer/video/platform/storage services with export dialogs acting only as UI adapters | | DEBT-0044 | Open | Modernization | Timelapse and animation MP4 export execution dispatch now consumes pure `pp_app_core` through `App::dialog_timelapse_export`, `App::dialog_export_mp4`, `pano_cli plan-export-menu`, `pano_cli plan-export-target --kind name`, `DocumentVideoExportServices`, and `src/legacy_document_export_services.*`, but the bridge still launches legacy desktop timelapse worker threads, calls `App::rec_export`, calls `Canvas::export_anim_mp4`, owns mobile/Web save callbacks, and emits success messages directly | Preserve current MP4/timelapse export behavior while video export moves toward app/document/renderer/video/platform/storage services | `pp_app_core_document_export_tests`; `pano_cli plan-export-menu --kind animation-mp4`; `pano_cli plan-export-menu --kind timelapse`; `pano_cli plan-export-target --kind name --doc-name demo --suffix -animation`; `pano_cli plan-export-target --kind name --doc-name demo --suffix -timelapse`; `ctest --preset desktop-fast --build-config Debug` | Timelapse and animation MP4 execution, desktop worker threading, frame readback/video encoding handoff, mobile/Web save callbacks, and success reporting are owned by injected app/document/renderer/video/platform/storage services with export dialogs acting only as UI adapters |
| DEBT-0045 | Open | Modernization | Options-menu preference execution now consumes pure `pp_app_core` through UI scale, viewport scale, RTL direction, VR-controller, auto-timelapse, and canvas cursor-mode callbacks plus `AppPreferenceServices` and `src/legacy_app_preference_services.*`, but the bridge still calls legacy `App::set_ui_scale`, `App::set_ui_rtl`, `NodeCanvas::set_density`, `NodeCanvas::set_cursor_visibility`, `App::rec_start`, `App::rec_stop`, and `Settings::save` directly | Preserve current options-menu behavior while preferences move toward app/UI/platform/storage services | `pp_app_core_app_preferences_tests`; `pano_cli plan-app-preferences --ui-scale 1.5 --display-density 2 --current-scale 1.6 --scale-option 1 --scale-option 1.5 --rtl`; `ctest --preset desktop-fast --build-config Debug`; `cmake --build --preset windows-msvc-default --config Debug --target PanoPainter` | Preference persistence, UI/layout direction, viewport density, cursor mode, VR-controller state, and auto-timelapse recording side effects are owned by injected app/UI/platform/storage services with options-menu callbacks acting only as UI adapters | | DEBT-0045 | Open | Modernization | Options-menu preference execution now consumes pure `pp_app_core` through UI scale, viewport scale, RTL direction, VR mode, VR-controller, auto-timelapse, and canvas cursor-mode callbacks plus `AppPreferenceServices` and `src/legacy_app_preference_services.*`, but the bridge still calls legacy `App::set_ui_scale`, `App::set_ui_rtl`, `App::vr_start`, `App::vr_stop`, `NodeCanvas::set_density`, `NodeCanvas::set_cursor_visibility`, `App::rec_start`, `App::rec_stop`, and `Settings::save` directly | Preserve current options-menu behavior while preferences move toward app/UI/platform/storage services | `pp_app_core_app_preferences_tests`; `pano_cli plan-app-preferences --ui-scale 1.5 --display-density 2 --current-scale 1.6 --scale-option 1 --scale-option 1.5 --rtl`; `ctest --preset desktop-fast --build-config Debug`; `cmake --build --preset windows-msvc-default --config Debug --target PanoPainter` | Preference persistence, UI/layout direction, viewport density, cursor mode, VR mode start/stop/failure handling, VR-controller state, and auto-timelapse recording side effects are owned by injected app/UI/platform/storage services with options-menu callbacks acting only as UI adapters |
## Closed Debt ## Closed Debt

View File

@@ -177,7 +177,7 @@ project-open, app-close, save, save-as, and save-version flows;
contracts while legacy canvas/project loading remains in place. contracts while legacy canvas/project loading remains in place.
`pp_app_core` also owns tested app preference plans for UI scale/font scale, `pp_app_core` also owns tested app preference plans for UI scale/font scale,
scale option selection, viewport scale, RTL layout direction, timelapse scale option selection, viewport scale, RTL layout direction, timelapse
recording toggles, VR controller enablement, and canvas cursor mode; recording toggles, VR mode start/stop, VR controller enablement, and canvas cursor mode;
the live tools/options menu and `pano_cli plan-app-preferences` consume those the live tools/options menu and `pano_cli plan-app-preferences` consume those
contracts. Options-menu preference execution now dispatches through contracts. Options-menu preference execution now dispatches through
`AppPreferenceServices` and `src/legacy_app_preference_services.*` before `AppPreferenceServices` and `src/legacy_app_preference_services.*` before
@@ -606,7 +606,7 @@ legacy UI/panel/canvas/platform adapters continue execution. The live animation
panel route now also checks animation panel visibility and applies animation panel route now also checks animation panel visibility and applies animation
panel layout state instead of using the grid panel by mistake. panel layout state instead of using the grid panel by mistake.
Options-menu preference callbacks now dispatch UI scale, viewport scale, RTL, Options-menu preference callbacks now dispatch UI scale, viewport scale, RTL,
VR-controller, auto-timelapse, and cursor-mode side effects through VR mode, VR-controller, auto-timelapse, and cursor-mode side effects through
`AppPreferenceServices` in `src/legacy_app_preference_services.*` before `AppPreferenceServices` in `src/legacy_app_preference_services.*` before
retained settings writes, recording lifecycle calls, and legacy canvas/UI retained settings writes, recording lifecycle calls, and legacy canvas/UI
adapters continue. adapters continue.
@@ -1357,7 +1357,7 @@ Results:
after options-menu preference execution moved behind app preference services. after options-menu preference execution moved behind app preference services.
- Focused preference CTest coverage passed for - Focused preference CTest coverage passed for
`pp_app_core_app_preferences_tests` and the app-preferences CLI smoke tests `pp_app_core_app_preferences_tests` and the app-preferences CLI smoke tests
after the live bridge split. after the live bridge split, including VR mode failed-start status coverage.
- `pp_app_core_document_recording_tests` passed, covering recording start/stop, - `pp_app_core_document_recording_tests` passed, covering recording start/stop,
clear, platform recorded-file cleanup, frame-count reset, export progress clear, platform recorded-file cleanup, frame-count reset, export progress
totals, and oversized progress-total clamping. totals, and oversized progress-total clamping.

View File

@@ -53,6 +53,7 @@ public:
virtual void apply_ui_scale(const ScaleApplicationPlan& plan) = 0; virtual void apply_ui_scale(const ScaleApplicationPlan& plan) = 0;
virtual void apply_viewport_scale(const ScaleApplicationPlan& plan) = 0; virtual void apply_viewport_scale(const ScaleApplicationPlan& plan) = 0;
virtual void apply_interface_direction(const InterfaceDirectionPlan& plan) = 0; virtual void apply_interface_direction(const InterfaceDirectionPlan& plan) = 0;
virtual bool apply_vr_mode_preference(const StoredBooleanPreferencePlan& plan) = 0;
virtual void apply_vr_controllers_preference(const StoredBooleanPreferencePlan& plan) = 0; virtual void apply_vr_controllers_preference(const StoredBooleanPreferencePlan& plan) = 0;
virtual void apply_timelapse_preference(const TimelapsePreferencePlan& plan) = 0; virtual void apply_timelapse_preference(const TimelapsePreferencePlan& plan) = 0;
virtual void apply_canvas_cursor_mode(const StoredIntegerPreferencePlan& plan) = 0; virtual void apply_canvas_cursor_mode(const StoredIntegerPreferencePlan& plan) = 0;
@@ -120,6 +121,11 @@ public:
return { enabled }; return { enabled };
} }
[[nodiscard]] constexpr StoredBooleanPreferencePlan plan_vr_mode_preference(bool enabled) noexcept
{
return { enabled };
}
[[nodiscard]] constexpr StoredIntegerPreferencePlan plan_canvas_cursor_mode(int mode) noexcept [[nodiscard]] constexpr StoredIntegerPreferencePlan plan_canvas_cursor_mode(int mode) noexcept
{ {
return { mode }; return { mode };
@@ -151,6 +157,16 @@ public:
return pp::foundation::Status::success(); return pp::foundation::Status::success();
} }
[[nodiscard]] inline pp::foundation::Status execute_vr_mode_preference(
bool enabled,
AppPreferenceServices& services)
{
if (!services.apply_vr_mode_preference(plan_vr_mode_preference(enabled))) {
return pp::foundation::Status::invalid_argument("VR mode could not start");
}
return pp::foundation::Status::success();
}
[[nodiscard]] inline pp::foundation::Status execute_vr_controllers_preference( [[nodiscard]] inline pp::foundation::Status execute_vr_controllers_preference(
bool enabled, bool enabled,
AppPreferenceServices& services) AppPreferenceServices& services)

View File

@@ -1159,19 +1159,14 @@ void App::init_menu_tools()
vr_btn->find<NodeCheckBox>("tools-vr-check")->on_value_changed = [this, main](Node* target, bool checked) vr_btn->find<NodeCheckBox>("tools-vr-check")->on_value_changed = [this, main](Node* target, bool checked)
{ {
if (checked) const auto status = pp::panopainter::execute_legacy_vr_mode_preference(
{ *this,
if (!vr_start()) checked);
{ if (!status.ok()) {
auto cb = static_cast<NodeCheckBox*>(target); auto cb = static_cast<NodeCheckBox*>(target);
cb->set_value(false); cb->set_value(false);
message_box("VR Failed", "Couldn't start Virtual Reality mode"); message_box("VR Failed", "Couldn't start Virtual Reality mode");
} }
}
else
{
vr_stop();
}
}; };
} }

View File

@@ -37,6 +37,16 @@ public:
app_.set_ui_rtl(plan.direction == pp::app::InterfaceDirection::right_to_left); app_.set_ui_rtl(plan.direction == pp::app::InterfaceDirection::right_to_left);
} }
bool apply_vr_mode_preference(const pp::app::StoredBooleanPreferencePlan& plan) override
{
if (plan.value) {
return app_.vr_start();
}
app_.vr_stop();
return true;
}
void apply_vr_controllers_preference(const pp::app::StoredBooleanPreferencePlan& plan) override void apply_vr_controllers_preference(const pp::app::StoredBooleanPreferencePlan& plan) override
{ {
app_.vr_controllers_enabled = plan.value; app_.vr_controllers_enabled = plan.value;
@@ -90,6 +100,12 @@ pp::foundation::Status execute_legacy_interface_direction_preference(App& app, b
return pp::app::execute_interface_direction_preference(right_to_left, services); return pp::app::execute_interface_direction_preference(right_to_left, services);
} }
pp::foundation::Status execute_legacy_vr_mode_preference(App& app, bool enabled)
{
LegacyAppPreferenceServices services(app);
return pp::app::execute_vr_mode_preference(enabled, services);
}
pp::foundation::Status execute_legacy_vr_controllers_preference(App& app, bool enabled) pp::foundation::Status execute_legacy_vr_controllers_preference(App& app, bool enabled)
{ {
LegacyAppPreferenceServices services(app); LegacyAppPreferenceServices services(app);

View File

@@ -15,6 +15,9 @@ namespace pp::panopainter {
[[nodiscard]] pp::foundation::Status execute_legacy_interface_direction_preference( [[nodiscard]] pp::foundation::Status execute_legacy_interface_direction_preference(
App& app, App& app,
bool right_to_left); bool right_to_left);
[[nodiscard]] pp::foundation::Status execute_legacy_vr_mode_preference(
App& app,
bool enabled);
[[nodiscard]] pp::foundation::Status execute_legacy_vr_controllers_preference( [[nodiscard]] pp::foundation::Status execute_legacy_vr_controllers_preference(
App& app, App& app,
bool enabled); bool enabled);

View File

@@ -28,6 +28,13 @@ public:
call_order += "direction;"; call_order += "direction;";
} }
bool apply_vr_mode_preference(const pp::app::StoredBooleanPreferencePlan& plan) override
{
vr_mode = plan.value;
call_order += "vr-mode;";
return vr_mode_result;
}
void apply_vr_controllers_preference(const pp::app::StoredBooleanPreferencePlan& plan) override void apply_vr_controllers_preference(const pp::app::StoredBooleanPreferencePlan& plan) override
{ {
vr_controllers = plan.value; vr_controllers = plan.value;
@@ -52,6 +59,8 @@ public:
float viewport_scale = 0.0F; float viewport_scale = 0.0F;
float viewport_font_scale = 0.0F; float viewport_font_scale = 0.0F;
pp::app::InterfaceDirection interface_direction = pp::app::InterfaceDirection::left_to_right; pp::app::InterfaceDirection interface_direction = pp::app::InterfaceDirection::left_to_right;
bool vr_mode = false;
bool vr_mode_result = true;
bool vr_controllers = false; bool vr_controllers = false;
bool timelapse_enabled = false; bool timelapse_enabled = false;
pp::app::TimelapseRecordingAction timelapse_action = pp::app::TimelapseRecordingAction::no_op; pp::app::TimelapseRecordingAction timelapse_action = pp::app::TimelapseRecordingAction::no_op;
@@ -120,6 +129,8 @@ void timelapse_preference_starts_and_stops_only_on_state_change(pp::tests::Harne
void simple_preferences_preserve_values_for_storage(pp::tests::Harness& harness) void simple_preferences_preserve_values_for_storage(pp::tests::Harness& harness)
{ {
PP_EXPECT(harness, pp::app::plan_vr_mode_preference(true).value);
PP_EXPECT(harness, !pp::app::plan_vr_mode_preference(false).value);
PP_EXPECT(harness, pp::app::plan_vr_controllers_preference(true).value); PP_EXPECT(harness, pp::app::plan_vr_controllers_preference(true).value);
PP_EXPECT(harness, !pp::app::plan_vr_controllers_preference(false).value); PP_EXPECT(harness, !pp::app::plan_vr_controllers_preference(false).value);
PP_EXPECT(harness, pp::app::plan_canvas_cursor_mode(2).value == 2); PP_EXPECT(harness, pp::app::plan_canvas_cursor_mode(2).value == 2);
@@ -132,6 +143,7 @@ void preference_executor_dispatches_side_effect_plans(pp::tests::Harness& harnes
PP_EXPECT(harness, pp::app::execute_ui_scale_preference(1.5F, 2.0F, services).ok()); PP_EXPECT(harness, pp::app::execute_ui_scale_preference(1.5F, 2.0F, services).ok());
PP_EXPECT(harness, pp::app::execute_viewport_scale_preference(1.25F, 1.0F, services).ok()); PP_EXPECT(harness, pp::app::execute_viewport_scale_preference(1.25F, 1.0F, services).ok());
PP_EXPECT(harness, pp::app::execute_interface_direction_preference(true, services).ok()); PP_EXPECT(harness, pp::app::execute_interface_direction_preference(true, services).ok());
PP_EXPECT(harness, pp::app::execute_vr_mode_preference(true, services).ok());
PP_EXPECT(harness, pp::app::execute_vr_controllers_preference(true, services).ok()); PP_EXPECT(harness, pp::app::execute_vr_controllers_preference(true, services).ok());
PP_EXPECT(harness, pp::app::execute_timelapse_preference(true, false, services).ok()); PP_EXPECT(harness, pp::app::execute_timelapse_preference(true, false, services).ok());
PP_EXPECT(harness, pp::app::execute_canvas_cursor_mode_preference(2, services).ok()); PP_EXPECT(harness, pp::app::execute_canvas_cursor_mode_preference(2, services).ok());
@@ -141,13 +153,14 @@ void preference_executor_dispatches_side_effect_plans(pp::tests::Harness& harnes
PP_EXPECT(harness, services.viewport_scale == 1.25F); PP_EXPECT(harness, services.viewport_scale == 1.25F);
PP_EXPECT(harness, services.viewport_font_scale == 1.25F); PP_EXPECT(harness, services.viewport_font_scale == 1.25F);
PP_EXPECT(harness, services.interface_direction == pp::app::InterfaceDirection::right_to_left); PP_EXPECT(harness, services.interface_direction == pp::app::InterfaceDirection::right_to_left);
PP_EXPECT(harness, services.vr_mode);
PP_EXPECT(harness, services.vr_controllers); PP_EXPECT(harness, services.vr_controllers);
PP_EXPECT(harness, services.timelapse_enabled); PP_EXPECT(harness, services.timelapse_enabled);
PP_EXPECT(harness, services.timelapse_action == pp::app::TimelapseRecordingAction::start_recording); PP_EXPECT(harness, services.timelapse_action == pp::app::TimelapseRecordingAction::start_recording);
PP_EXPECT(harness, services.cursor_mode == 2); PP_EXPECT(harness, services.cursor_mode == 2);
PP_EXPECT( PP_EXPECT(
harness, harness,
services.call_order == "ui-scale;viewport-scale;direction;vr-controllers;timelapse;cursor;"); services.call_order == "ui-scale;viewport-scale;direction;vr-mode;vr-controllers;timelapse;cursor;");
} }
void preference_executor_preserves_timelapse_stop_action(pp::tests::Harness& harness) void preference_executor_preserves_timelapse_stop_action(pp::tests::Harness& harness)
@@ -159,6 +172,17 @@ void preference_executor_preserves_timelapse_stop_action(pp::tests::Harness& har
PP_EXPECT(harness, services.timelapse_action == pp::app::TimelapseRecordingAction::stop_recording); PP_EXPECT(harness, services.timelapse_action == pp::app::TimelapseRecordingAction::stop_recording);
} }
void preference_executor_reports_failed_vr_start(pp::tests::Harness& harness)
{
FakeAppPreferenceServices services;
services.vr_mode_result = false;
const auto status = pp::app::execute_vr_mode_preference(true, services);
PP_EXPECT(harness, !status.ok());
PP_EXPECT(harness, status.code == pp::foundation::StatusCode::invalid_argument);
PP_EXPECT(harness, services.vr_mode);
}
} }
int main() int main()
@@ -178,5 +202,6 @@ int main()
harness.run("simple preferences preserve values for storage", simple_preferences_preserve_values_for_storage); harness.run("simple preferences preserve values for storage", simple_preferences_preserve_values_for_storage);
harness.run("preference executor dispatches side effect plans", preference_executor_dispatches_side_effect_plans); harness.run("preference executor dispatches side effect plans", preference_executor_dispatches_side_effect_plans);
harness.run("preference executor preserves timelapse stop action", preference_executor_preserves_timelapse_stop_action); harness.run("preference executor preserves timelapse stop action", preference_executor_preserves_timelapse_stop_action);
harness.run("preference executor reports failed VR start", preference_executor_reports_failed_vr_start);
return harness.finish(); return harness.finish();
} }