Files
t-embed-insecam-widget/main/settings.c
T
Juli 3bdfcba6fb Selectable UI themes and a Popular source
Themes (Phosphor, Pink, Amber, Ice, Terminal) restyle the menu, boot
page and toasts live from the menu; all but Terminal use readable
Montserrat text. Source gains Popular: the top-rated listings walked in
rank order from page 1, alternating providers when mixed.
2026-09-17 03:11:25 +02:00

131 lines
4.3 KiB
C

#include "settings.h"
#include "ui.h"
#include "sdkconfig.h"
#include "esp_log.h"
#include "nvs.h"
#include "nvs_flash.h"
#include "esp_heap_caps.h"
#include <assert.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
static const char *TAG = "settings";
static nvs_handle_t nvs;
settings_t settings;
static cam_info_t *favs; // FAV_SLOTS entries, in PSRAM
static bool fav_used[FAV_SLOTS];
static void slot_key(int slot, char *key) { snprintf(key, 8, "fav%d", slot); }
void settings_init(void)
{
esp_err_t err = nvs_flash_init();
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
err = nvs_flash_init();
}
ESP_ERROR_CHECK(err);
ESP_ERROR_CHECK(nvs_open("widget", NVS_READWRITE, &nvs));
settings = (settings_t){
.interval_s = CONFIG_WIDGET_INTERVAL_S, .lcd_brightness = CONFIG_WIDGET_LCD_BRIGHTNESS,
.led_brightness = CONFIG_WIDGET_LED_BRIGHTNESS,
#if CONFIG_WIDGET_LISTING_RATING
.listing = LISTING_RATING,
#elif CONFIG_WIDGET_LISTING_NEW
.listing = LISTING_NEW,
#else
.listing = LISTING_MIXED,
#endif
.source = SOURCE_RANDOM, .caption = 1, .provider = PROVIDER_PREF_MIXED, .version = SETTINGS_VERSION,
};
// Blobs written by older builds may be shorter: copy what is there over the defaults.
settings_t stored = settings;
size_t len = sizeof stored;
if (nvs_get_blob(nvs, "settings", &stored, &len) == ESP_OK && len >= 7 && len <= sizeof stored) {
memcpy(&settings, &stored, len);
if (len <= offsetof(settings_t, provider)) settings.provider = PROVIDER_PREF_MIXED; // pre-provider blob
settings.version = SETTINGS_VERSION;
if (settings.interval_s < 5 || settings.interval_s > 300) settings.interval_s = CONFIG_WIDGET_INTERVAL_S;
if (settings.lcd_brightness > 100) settings.lcd_brightness = 100;
if (settings.listing > LISTING_NEW) settings.listing = LISTING_MIXED;
if (settings.source > SOURCE_POPULAR) settings.source = SOURCE_RANDOM;
if (settings.theme >= ui_theme_count()) settings.theme = 0;
if (settings.provider > PROVIDER_PREF_MIXED) settings.provider = PROVIDER_PREF_MIXED;
}
favs = heap_caps_calloc(FAV_SLOTS, sizeof *favs, MALLOC_CAP_SPIRAM);
assert(favs);
for (int i = 0; i < FAV_SLOTS; i++) {
char key[8];
slot_key(i, key);
len = sizeof favs[i];
fav_used[i] = nvs_get_blob(nvs, key, &favs[i], &len) == ESP_OK && len <= sizeof favs[i] && favs[i].url[0];
if (fav_used[i] && favs[i].provider > PROVIDER_OPENTOPIA) favs[i].provider = PROVIDER_INSECAM;
}
ESP_LOGI(TAG, "interval %us, lcd %u%%, ring %u, listing %u, source %u, provider %u, %d favourites",
settings.interval_s, settings.lcd_brightness, settings.led_brightness, settings.listing,
settings.source, settings.provider, fav_count());
}
void settings_save(void)
{
if (nvs_set_blob(nvs, "settings", &settings, sizeof settings) != ESP_OK || nvs_commit(nvs) != ESP_OK)
ESP_LOGW(TAG, "save failed");
}
void settings_request_portal(void)
{
nvs_set_u8(nvs, "portal", 1);
nvs_commit(nvs);
}
bool settings_take_portal_request(void)
{
uint8_t v = 0;
if (nvs_get_u8(nvs, "portal", &v) != ESP_OK || !v) return false;
nvs_erase_key(nvs, "portal");
nvs_commit(nvs);
return true;
}
const cam_info_t *fav_get(int slot)
{
return (slot >= 0 && slot < FAV_SLOTS && fav_used[slot]) ? &favs[slot] : NULL;
}
void fav_set(int slot, const cam_info_t *cam)
{
if (slot < 0 || slot >= FAV_SLOTS) return;
char key[8];
slot_key(slot, key);
favs[slot] = *cam;
fav_used[slot] = true;
if (nvs_set_blob(nvs, key, &favs[slot], sizeof favs[slot]) != ESP_OK || nvs_commit(nvs) != ESP_OK)
ESP_LOGW(TAG, "favourite %d not saved", slot);
}
void fav_clear(int slot)
{
if (slot < 0 || slot >= FAV_SLOTS) return;
char key[8];
slot_key(slot, key);
fav_used[slot] = false;
nvs_erase_key(nvs, key);
nvs_commit(nvs);
}
int fav_find(const cam_info_t *cam)
{
for (int i = 0; i < FAV_SLOTS; i++)
if (fav_used[i] && favs[i].id == cam->id && favs[i].provider == cam->provider) return i;
return -1;
}
int fav_count(void)
{
int n = 0;
for (int i = 0; i < FAV_SLOTS; i++) n += fav_used[i];
return n;
}