Login
1 branch 0 tags
Ben (Desktop/Arch) Limited podcast episode list to 16 entries b36bce8 29 days ago 80 Commits
moon / src / ui.h
#pragma once
#include <stdint.h>
#include "lvgl.h"
#include "playlist.h"
#include "storage.h"

// Screen types enum
typedef enum {
	SCREEN_NONE = 0,
	SCREEN_HOME,
	SCREEN_FILES,
	SCREEN_NOW_PLAYING,
	SCREEN_QUEUE_DIALOG,
	SCREEN_AUDIOBOOKS,
	SCREEN_MUSIC,
	SCREEN_SETTINGS,
	SCREEN_USB,
	SCREEN_CONFIRM,
	SCREEN_PODCASTS,
	SCREEN_PODCAST_FEED,
	SCREEN_PODCAST_SYNC,
	SCREEN_PODCAST_EPISODE,
	SCREEN_WIFI,
} screen_type_t;

// Animation direction for screen transitions
typedef enum { ANIM_NONE, ANIM_FORWARD, ANIM_BACK } anim_dir_t;
#define ANIM_DURATION_MS 200

// Global app config (available to all screens)
typedef struct {
	uint8_t volume;              // 0-100
	uint8_t brightness;          // 0-100
	char last_played_path[256];  // Path of last played file for navigation
	char audiobook_dir[256];     // Non-empty = directory playback mode
	char podcast_dir[STORAGE_MAX_PATH];  // Current podcast feed directory
	char podcast_episode_dir[STORAGE_MAX_PATH];  // Current episode directory
	char podcast_title[128];                     // For single-feed sync
	char podcast_url[256];                       // For single-feed sync

	// Queue dialog context
	char pending_path[256];
	playlist_type_t pending_type;
	screen_type_t return_screen;
	char return_cwd[STORAGE_MAX_PATH];
	char return_focus[STORAGE_MAX_NAME];
} app_state_t;

#ifdef ESP_PLATFORM
#include "esp_log.h"
#endif

#ifndef ESP_PLATFORM
#define ESP_LOGI(_TAG_, ...) fprintf(stderr, _TAG_ ": " __VA_ARGS__)
#endif

// Forward declarations for screen state types
typedef struct home_screen_state home_screen_state_t;
typedef struct files_screen_state files_screen_state_t;
typedef struct now_playing_screen_state now_playing_screen_state_t;
typedef struct queue_dialog_screen_state queue_dialog_screen_state_t;
typedef struct audiobooks_screen_state audiobooks_screen_state_t;
typedef struct music_screen_state music_screen_state_t;
typedef struct settings_screen_state settings_screen_state_t;
typedef struct usb_screen_state usb_screen_state_t;
typedef struct confirm_screen_state confirm_screen_state_t;
typedef struct podcasts_screen_state podcasts_screen_state_t;
typedef struct podcast_feed_screen_state podcast_feed_screen_state_t;
typedef struct podcast_sync_screen_state podcast_sync_screen_state_t;
typedef struct podcast_episode_screen_state podcast_episode_screen_state_t;
typedef struct wifi_screen_state wifi_screen_state_t;

// Tagged union for current screen state
typedef struct {
	screen_type_t type;
	union {
		home_screen_state_t* home;
		files_screen_state_t* files;
		now_playing_screen_state_t* now_playing;
		queue_dialog_screen_state_t* queue_dialog;
		audiobooks_screen_state_t* audiobooks;
		music_screen_state_t* music;
		settings_screen_state_t* settings;
		usb_screen_state_t* usb;
		confirm_screen_state_t* confirm;
		podcasts_screen_state_t* podcasts;
		podcast_feed_screen_state_t* podcast_feed;
		podcast_sync_screen_state_t* podcast_sync;
		podcast_episode_screen_state_t* podcast_episode;
		wifi_screen_state_t* wifi;
	};
} ui_state_t;

// Globals
extern app_state_t app_state;
extern ui_state_t ui_state;
extern char string_buffer[256];

// Dispatch functions
ui_state_t setup_screen(screen_type_t type, lv_obj_t* parent);
void free_screen(void);
void update_screen(void);

// Navigation helpers for animated screen transitions
lv_obj_t* navigate_prepare(anim_dir_t dir);
void navigate_commit(void);

// Navigate forward (slide left) to a screen
#define navigate_to(screen_type)                         \
	do {                                                 \
		lv_obj_t* _scr = navigate_prepare(ANIM_FORWARD); \
		ui_state = setup_screen(screen_type, _scr);      \
		navigate_commit();                               \
	} while (0)

// Navigate back (slide right) to a screen
#define navigate_back(screen_type)                    \
	do {                                              \
		lv_obj_t* _scr = navigate_prepare(ANIM_BACK); \
		ui_state = setup_screen(screen_type, _scr);   \
		navigate_commit();                            \
	} while (0)

// Navigate without animation
#define navigate_none(screen_type)                    \
	do {                                              \
		lv_obj_t* _scr = navigate_prepare(ANIM_NONE); \
		ui_state = setup_screen(screen_type, _scr);   \
		navigate_commit();                            \
	} while (0)

// Confirm dialog
typedef void (*confirm_cb_t)(void);
void navigate_to_confirm(const char* title,
                         confirm_cb_t on_confirm,
                         screen_type_t return_screen);
ui_state_t setup_confirm_screen(lv_obj_t* parent);
void free_confirm_screen(confirm_screen_state_t* state);

lv_obj_t* bvs_list_add_button(lv_obj_t* list,
                              const void* icon,
                              const char* txt);
lv_obj_t* bvs_list_add_nav_button(lv_obj_t* list,
                                  const void* icon,
                                  const char* txt,
                                  lv_event_cb_t click_cb,
                                  void* click_data,
                                  lv_event_cb_t cancel_cb);
lv_obj_t* bvs_list_create(lv_obj_t* parent);
void bvs_list_clear(lv_obj_t* list);

// File browser utilities shared by files/music/audiobooks screens
void path_parent(const char* path,
                 char* parent,
                 size_t parent_size,
                 char* basename,
                 size_t basename_size);
int entry_name_cmp(const void* a, const void* b);
int get_sorted_entries(const char* dir,
                       storage_entry_t* entries,
                       int max_entries);
bool get_entry_at_index(const char* dir, int index, storage_entry_t* out);

// Queue dialog helper
void show_queue_dialog(const char* path,
                       playlist_type_t type,
                       screen_type_t return_screen,
                       const char* cwd,
                       const char* focus_name);