feat: add AppRegistry, RootLayout, UIHandler, and UIApp classes for improved UI management
This commit is contained in:
39
main/ui/app_registry.h
Normal file
39
main/ui/app_registry.h
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "ui/ui_app.h"
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Registry for all available apps
|
||||||
|
*
|
||||||
|
* This singleton class maintains a list of all registered
|
||||||
|
* AppDescriptor instances, allowing the UIHandler or other
|
||||||
|
* components to query available apps.
|
||||||
|
*/
|
||||||
|
class AppRegistry {
|
||||||
|
public:
|
||||||
|
static AppRegistry& instance() {
|
||||||
|
static AppRegistry registry;
|
||||||
|
return registry;
|
||||||
|
}
|
||||||
|
|
||||||
|
AppRegistry(const AppRegistry&) = delete;
|
||||||
|
void operator=(const AppRegistry&) = delete;
|
||||||
|
AppRegistry(AppRegistry&&) = delete;
|
||||||
|
void operator=(AppRegistry&&) = delete;
|
||||||
|
|
||||||
|
|
||||||
|
// Register a new app descriptor
|
||||||
|
// The registry takes ownership of the descriptor pointer.
|
||||||
|
void register_app(AppDescriptor* app_descriptor) {
|
||||||
|
_app_descriptors.push_back(app_descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<AppDescriptor*>& get_app_descriptors() const {
|
||||||
|
return _app_descriptors;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
AppRegistry() = default;
|
||||||
|
~AppRegistry() = default;
|
||||||
|
std::vector<AppDescriptor*> _app_descriptors = {};
|
||||||
|
};
|
||||||
138
main/ui/root_layout.h
Normal file
138
main/ui/root_layout.h
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "lvgl.h"
|
||||||
|
#include "esp_err.h"
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
// Forward declaration
|
||||||
|
class UIHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Root Layout Manager - manages the main screen layout
|
||||||
|
*
|
||||||
|
* The RootLayout class is responsible for:
|
||||||
|
* - Creating and managing the main screen structure (header, app container, nav bar)
|
||||||
|
* - Rendering app icons from the AppRegistry
|
||||||
|
* - Managing the back button
|
||||||
|
* - Updating header content
|
||||||
|
*/
|
||||||
|
class RootLayout {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Construct a new RootLayout object
|
||||||
|
*
|
||||||
|
* @param ui_handler Pointer to the UIHandler (for callbacks)
|
||||||
|
*/
|
||||||
|
RootLayout(UIHandler* ui_handler);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize the layout
|
||||||
|
*
|
||||||
|
* Creates the main screen with header, app container, and navigation bar.
|
||||||
|
*
|
||||||
|
* @param parent Parent LVGL object to attach layout to
|
||||||
|
* @return ESP_OK on success, error code otherwise
|
||||||
|
*/
|
||||||
|
esp_err_t init(lv_obj_t* parent);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Deinitialize the layout
|
||||||
|
*
|
||||||
|
* Cleans up all layout widgets.
|
||||||
|
*
|
||||||
|
* @return ESP_OK on success, error code otherwise
|
||||||
|
*/
|
||||||
|
esp_err_t deinit(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Render app icons in the navigation bar
|
||||||
|
*
|
||||||
|
* Queries the AppRegistry for all registered apps and
|
||||||
|
* renders their icons in the navigation bar. Also creates
|
||||||
|
* the back button.
|
||||||
|
*
|
||||||
|
* @return ESP_OK on success, error code otherwise
|
||||||
|
*/
|
||||||
|
esp_err_t render_app_icons(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Update header with app name
|
||||||
|
*
|
||||||
|
* @param app_name Name to display in header (nullptr for default)
|
||||||
|
*/
|
||||||
|
void update_header(std::string app_name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Show the back button
|
||||||
|
*/
|
||||||
|
void show_back_button(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Hide the back button
|
||||||
|
*/
|
||||||
|
void hide_back_button(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the header object
|
||||||
|
*
|
||||||
|
* @return lv_obj_t* pointer to the header container
|
||||||
|
*/
|
||||||
|
lv_obj_t* get_header(void) const {
|
||||||
|
return _header;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the app container (where apps render)
|
||||||
|
*
|
||||||
|
* @return lv_obj_t* pointer to the app container
|
||||||
|
*/
|
||||||
|
lv_obj_t* get_app_container(void) const {
|
||||||
|
return _app_container;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the navigation bar object
|
||||||
|
*
|
||||||
|
* @return lv_obj_t* pointer to the navigation bar container
|
||||||
|
*/
|
||||||
|
lv_obj_t* get_nav_bar(void) const {
|
||||||
|
return _nav_bar;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
UIHandler* _ui_handler = nullptr; ///< Reference to UIHandler for callbacks
|
||||||
|
lv_obj_t* _header = nullptr; ///< Header area (top)
|
||||||
|
lv_obj_t* _header_label = nullptr; ///< Header text label
|
||||||
|
lv_obj_t* _app_container = nullptr; ///< Container for app widgets (middle)
|
||||||
|
lv_obj_t* _nav_bar = nullptr; ///< Navigation bar (bottom)
|
||||||
|
lv_obj_t* _back_button = nullptr; ///< Back button in navigation bar
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create the layout structure
|
||||||
|
*
|
||||||
|
* Sets up header, app container, and navigation bar with
|
||||||
|
* appropriate dimensions and positioning.
|
||||||
|
*
|
||||||
|
* @param parent Parent object to attach layout to
|
||||||
|
* @return ESP_OK on success, error code otherwise
|
||||||
|
*/
|
||||||
|
esp_err_t create_layout(lv_obj_t* parent);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handle app icon click event
|
||||||
|
*
|
||||||
|
* Static callback for LVGL event handling.
|
||||||
|
*
|
||||||
|
* @param event LVGL event object
|
||||||
|
*/
|
||||||
|
static void on_app_icon_clicked(lv_event_t* event);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handle back button click event
|
||||||
|
*
|
||||||
|
* Static callback for LVGL event handling.
|
||||||
|
*
|
||||||
|
* @param event LVGL event object
|
||||||
|
*/
|
||||||
|
static void on_back_button_clicked(lv_event_t* event);
|
||||||
|
};
|
||||||
98
main/ui/ui_app.h
Normal file
98
main/ui/ui_app.h
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "lvgl.h"
|
||||||
|
#include "esp_err.h"
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Base class for all UI applications
|
||||||
|
*
|
||||||
|
* All UI applications (apps) must inherit from this class.
|
||||||
|
* Each app is responsible for managing its own widgets within
|
||||||
|
* the provided LVGL container. The UIHandler will manage the
|
||||||
|
* lifecycle of apps and event routing.
|
||||||
|
*/
|
||||||
|
class UIApp {
|
||||||
|
public:
|
||||||
|
virtual ~UIApp() = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize the app with the given container
|
||||||
|
*
|
||||||
|
* The app should create all its widgets as children of the
|
||||||
|
* provided container. The container is already positioned
|
||||||
|
* between the header and navigation bar.
|
||||||
|
*
|
||||||
|
* @param container LVGL container object for this app
|
||||||
|
* @return ESP_OK on success, error code otherwise
|
||||||
|
*/
|
||||||
|
virtual esp_err_t init(lv_obj_t* container) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Deinitialize and clean up app resources
|
||||||
|
*
|
||||||
|
* The app should delete all widgets and release any resources.
|
||||||
|
* The container itself will be handled by UIHandler.
|
||||||
|
*
|
||||||
|
* @return ESP_OK on success, error code otherwise
|
||||||
|
*/
|
||||||
|
virtual esp_err_t deinit(void) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the display name of this app
|
||||||
|
*
|
||||||
|
* Used for logging and potentially showing in navigation.
|
||||||
|
*
|
||||||
|
* @return std::string app name
|
||||||
|
*/
|
||||||
|
virtual std::string get_name(void) const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handle system events passed from UIHandler
|
||||||
|
*
|
||||||
|
* System events include network status changes, storage ready,
|
||||||
|
* display refresh, and other system-level events.
|
||||||
|
*
|
||||||
|
* @param event_type Type/ID of the event
|
||||||
|
* @param event_data Optional event data payload
|
||||||
|
*/
|
||||||
|
virtual void handle_event(uint32_t event_type, void* event_data = nullptr) { }
|
||||||
|
|
||||||
|
virtual bool on_back_button_pressed(void) {
|
||||||
|
return false; // default: not handled
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the app's root container
|
||||||
|
*
|
||||||
|
* @return lv_obj_t* pointer to the app's container
|
||||||
|
*/
|
||||||
|
lv_obj_t* get_container(void) const {
|
||||||
|
return _container;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
lv_obj_t* _container = nullptr; ///< LVGL container provided by UIHandler
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class AppDescriptor {
|
||||||
|
public:
|
||||||
|
virtual ~AppDescriptor() = default;
|
||||||
|
virtual void draw_icon(lv_obj_t* parent) = 0;
|
||||||
|
|
||||||
|
std::string get_name() const {
|
||||||
|
return _name;
|
||||||
|
}
|
||||||
|
|
||||||
|
UIApp* get_app_instance() const {
|
||||||
|
return _app_instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
AppDescriptor(std::string name, UIApp* app_instance)
|
||||||
|
: _name(name), _app_instance(app_instance) { }
|
||||||
|
|
||||||
|
std::string _name;
|
||||||
|
UIApp* _app_instance;
|
||||||
|
};
|
||||||
147
main/ui/ui_handler.h
Normal file
147
main/ui/ui_handler.h
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ui_app.h"
|
||||||
|
#include "app_registry.h"
|
||||||
|
#include "root_layout.h"
|
||||||
|
#include "esp_err.h"
|
||||||
|
|
||||||
|
// Forward declaration
|
||||||
|
class RootLayout;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief UI Handler - manages app lifecycle and rendering
|
||||||
|
*
|
||||||
|
* The UIHandler manages:
|
||||||
|
* - Creation and destruction of UI apps
|
||||||
|
* - Switching between apps
|
||||||
|
* - Main screen layout (header, app container, navigation bar)
|
||||||
|
* - System event routing to active app
|
||||||
|
* - Displaying special screens (shutdown, etc.)
|
||||||
|
*/
|
||||||
|
class UIHandler {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Initialize the UI system with default layout
|
||||||
|
*
|
||||||
|
* Creates the main screen with:
|
||||||
|
* - Header area (top)
|
||||||
|
* - App container (middle)
|
||||||
|
* - Navigation bar (bottom)
|
||||||
|
*
|
||||||
|
* @return ESP_OK on success, error code otherwise
|
||||||
|
*/
|
||||||
|
esp_err_t init(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Deinitialize the UI system
|
||||||
|
*
|
||||||
|
* Cleans up the current app and destroys the main screen.
|
||||||
|
*
|
||||||
|
* @return ESP_OK on success, error code otherwise
|
||||||
|
*/
|
||||||
|
esp_err_t deinit(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Switch to a new app
|
||||||
|
*
|
||||||
|
* Deinitializes the current app (if any), initializes the new app,
|
||||||
|
* and updates the display.
|
||||||
|
*
|
||||||
|
* @param app Pointer to the new app to switch to
|
||||||
|
* @return ESP_OK on success, error code otherwise
|
||||||
|
*/
|
||||||
|
esp_err_t switch_app(UIApp* app);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Switch to an app by its descriptor
|
||||||
|
*
|
||||||
|
* Convenience method that extracts the UIApp from the descriptor
|
||||||
|
* and calls switch_app().
|
||||||
|
*
|
||||||
|
* @param app_descriptor Pointer to the app descriptor
|
||||||
|
* @return ESP_OK on success, error code otherwise
|
||||||
|
*/
|
||||||
|
esp_err_t switch_app(AppDescriptor* app_descriptor);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the currently active app
|
||||||
|
*
|
||||||
|
* @return Pointer to the active UIApp, or nullptr if none
|
||||||
|
*/
|
||||||
|
UIApp* get_active_app(void) const {
|
||||||
|
return _active_app;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Route a system event to the active app
|
||||||
|
*
|
||||||
|
* If an app is active, this forwards the event to it.
|
||||||
|
*
|
||||||
|
* @param event_type Type/ID of the event
|
||||||
|
* @param event_data Optional event data payload
|
||||||
|
*/
|
||||||
|
void route_event(uint32_t event_type, void* event_data = nullptr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Display shutdown screen
|
||||||
|
*
|
||||||
|
* Shows a shutdown screen with a message. Typically called
|
||||||
|
* before the system enters deep sleep or powers off.
|
||||||
|
*
|
||||||
|
* @param message Optional message to display (e.g., "Shutting down...")
|
||||||
|
* @return ESP_OK on success, error code otherwise
|
||||||
|
*/
|
||||||
|
esp_err_t show_shutdown_screen(std::string message = "");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the main screen object
|
||||||
|
*
|
||||||
|
* @return lv_obj_t* pointer to the main screen
|
||||||
|
*/
|
||||||
|
lv_obj_t* get_main_screen(void) const {
|
||||||
|
return _main_screen;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the app container (where apps render)
|
||||||
|
*
|
||||||
|
* @return lv_obj_t* pointer to the app container
|
||||||
|
*/
|
||||||
|
lv_obj_t* get_app_container(void) const {
|
||||||
|
return _root_layout ? _root_layout->get_app_container() : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the header object
|
||||||
|
*
|
||||||
|
* @return lv_obj_t* pointer to the header container
|
||||||
|
*/
|
||||||
|
lv_obj_t* get_header(void) const {
|
||||||
|
return _root_layout ? _root_layout->get_header() : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the navigation bar object
|
||||||
|
*
|
||||||
|
* @return lv_obj_t* pointer to the navigation bar container
|
||||||
|
*/
|
||||||
|
lv_obj_t* get_nav_bar(void) const {
|
||||||
|
return _root_layout ? _root_layout->get_nav_bar() : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return to main screen (deinit app and show app icons)
|
||||||
|
*
|
||||||
|
* Deinitializes the active app and displays the app icons
|
||||||
|
* in the navigation bar, returning to the home screen.
|
||||||
|
*
|
||||||
|
* @return ESP_OK on success, error code otherwise
|
||||||
|
*/
|
||||||
|
esp_err_t return_to_main_screen(void);
|
||||||
|
|
||||||
|
private:
|
||||||
|
lv_obj_t* _main_screen = nullptr; ///< Root screen
|
||||||
|
RootLayout* _root_layout = nullptr; ///< Root layout manager
|
||||||
|
UIApp* _active_app = nullptr; ///< Currently active app
|
||||||
|
UIApp* _shutdown_app = nullptr; ///< Cached shutdown app
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user