#pragma once #include "ui/ui_app.h" #include "ui/page_stack.h" #include "ui/app_registry.h" #include "network/udp_client.h" #include "io/nvs_handler.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/semphr.h" #include /** * @brief Discord voice control app * * Allows control of Discord voice settings (mute/unmute) via UDP communication * with the IotDis Node.js bridge. Features: * - Main page: Status icon + mute button * - Settings page: IP/port configuration with connection test * - Periodic status polling with automatic retry * - Error notification when remote is unreachable */ class DiscordApp : public UIApp { public: DiscordApp(); ~DiscordApp() override; // UIApp interface esp_err_t init(lv_obj_t* container) override; esp_err_t deinit() override; std::string get_name() const override { return "Discord"; } void handle_event(uint32_t event_type, void* event_data = nullptr) override; bool on_back_button_pressed() override; private: // Voice state enum enum class VoiceState { UNKNOWN, MUTED, UNMUTED, ERROR }; // Page management PageStack* page_stack_; void build_main_page(lv_obj_t* page); void build_settings_page(lv_obj_t* page); void show_settings_page(); // Main page widgets lv_obj_t* status_icon_label_; lv_obj_t* status_text_label_; lv_obj_t* mute_button_; lv_obj_t* error_notification_; // Settings page widgets lv_obj_t* ip_textarea_; lv_obj_t* port_textarea_; lv_obj_t* test_result_label_; // UDP client and configuration UDPClient udp_client_; std::string remote_ip_; uint16_t remote_port_; bool settings_configured_; // Voice state VoiceState current_state_; SemaphoreHandle_t state_mutex_; // Polling task TaskHandle_t poll_task_handle_; bool stop_polling_; int consecutive_failures_; static constexpr int MAX_FAILURES_BEFORE_ERROR = 3; static constexpr int POLL_INTERVAL_MS = 5000; static constexpr int ERROR_POLL_INTERVAL_MS = 15000; static constexpr int RESPONSE_TIMEOUT_MS = 2000; // NVS storage NVSStorageHandler* storage_; static constexpr const char* NVS_NAMESPACE = "discord"; static constexpr const char* NVS_KEY_IP = "remote_ip"; static constexpr const char* NVS_KEY_PORT = "remote_port"; // Event callbacks static void on_mute_button_clicked(lv_event_t* e); static void on_settings_button_clicked(lv_event_t* e); static void on_save_settings_clicked(lv_event_t* e); static void on_test_connection_clicked(lv_event_t* e); // UDP communication void send_mute_command(); bool test_connection(); void update_status_display(); void show_error_notification(bool show); // Settings management void load_settings(); void save_settings(); // Polling task static void poll_task(void* param); void start_polling_task(); void stop_polling_task(); void poll_status(); }; /** * @brief Discord app descriptor for registration */ class DiscordAppDescriptor : public AppDescriptor { public: static DiscordAppDescriptor& instance() { static DiscordAppDescriptor instance; return instance; } void draw_icon(lv_obj_t* parent) override; private: DiscordAppDescriptor(); };