// D:\Dev\Mosis\MosisService\designer\src\testing\action_player.h #pragma once #include "action_types.h" #include #include #include namespace mosis::testing { class ActionPlayer { public: using ScreenshotCallback = std::function; using NavigateCallback = std::function; ActionPlayer(Rml::Context* context); ~ActionPlayer() = default; // Load and play bool LoadSequence(const ActionSequence& sequence); bool LoadFromFile(const std::string& path); // Playback control void Start(); void Stop(); void Pause(); void Resume(); bool IsPlaying() const { return m_playing && !m_paused; } bool IsPaused() const { return m_paused; } bool IsFinished() const { return m_finished; } // Call this every frame to advance playback void Update(); // Callbacks void SetScreenshotCallback(ScreenshotCallback cb) { m_screenshot_cb = std::move(cb); } void SetNavigateCallback(NavigateCallback cb) { m_navigate_cb = std::move(cb); } // Get progress size_t GetCurrentActionIndex() const { return m_current_index; } size_t GetTotalActions() const { return m_sequence.actions.size(); } float GetProgress() const; private: void ExecuteAction(const Action& action); void SimulateTap(int x, int y); void SimulateSwipe(int x1, int y1, int x2, int y2, int duration_ms); void SimulateLongPress(int x, int y, int duration_ms); void SimulateButton(const std::string& button); Rml::Context* m_context; ActionSequence m_sequence; bool m_playing = false; bool m_paused = false; bool m_finished = false; size_t m_current_index = 0; std::chrono::steady_clock::time_point m_start_time; std::chrono::steady_clock::time_point m_pause_time; int64_t m_paused_duration_ms = 0; int64_t m_min_finish_time_ms = 0; // Extended by wait actions ScreenshotCallback m_screenshot_cb; NavigateCallback m_navigate_cb; }; } // namespace mosis::testing