124 lines
3.3 KiB
C++
124 lines
3.3 KiB
C++
#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 <string>
|
|
|
|
/**
|
|
* @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();
|
|
};
|