#pragma once #include #include #include #include #include #include #include "Activity.h" /** * ListSelectionActivity is a reusable base class for activities that display * a scrollable list of items with selection capabilities. * * Features: * - Automatic pagination based on screen size * - Page skipping when holding navigation buttons * - Configurable title, empty message, and button labels */ class ListSelectionActivity : public Activity { protected: TaskHandle_t displayTaskHandle = nullptr; SemaphoreHandle_t renderingMutex = nullptr; size_t selectorIndex = 0; bool updateRequired = false; unsigned long enterTime = 0; // Configuration std::string title; std::string emptyMessage; std::string backLabel; std::string confirmLabel; std::function getItemCount; std::function getItemText; std::function onItemSelected; std::function onBack; // Constants static constexpr int SKIP_PAGE_MS = 700; static constexpr unsigned long IGNORE_INPUT_MS = 300; static constexpr int LINE_HEIGHT = 30; static constexpr int START_Y = 60; static constexpr int BOTTOM_BAR_HEIGHT = 60; static void taskTrampoline(void* param); [[noreturn]] void displayTaskLoop(); void render() const; int getPageItems() const; virtual void loadItems() {} // Override to load items on enter public: explicit ListSelectionActivity(const std::string& activityName, GfxRenderer& renderer, MappedInputManager& mappedInput, const std::string& title, std::function getItemCount, std::function getItemText, std::function onItemSelected, std::function onBack, const std::string& emptyMessage = "No items available", const std::string& backLabel = "« Back", const std::string& confirmLabel = "Select") : Activity(activityName, renderer, mappedInput), title(title), emptyMessage(emptyMessage), backLabel(backLabel), confirmLabel(confirmLabel), getItemCount(getItemCount), getItemText(getItemText), onItemSelected(onItemSelected), onBack(onBack) {} virtual ~ListSelectionActivity() = default; void onEnter() override; void onExit() override; void loop() override; // Allow subclasses to set initial selection void setInitialSelection(size_t index) { selectorIndex = index; } size_t getCurrentSelection() const { return selectorIndex; } };