diff --git a/src/system_fsm/booting.cpp b/src/system_fsm/booting.cpp index f33d1679..cdbe4d55 100644 --- a/src/system_fsm/booting.cpp +++ b/src/system_fsm/booting.cpp @@ -49,29 +49,23 @@ auto Booting::entry() -> void { sSamd.reset(drivers::Samd::Create()); sAdc.reset(drivers::AdcBattery::Create()); - assert(sSamd.get() && sAdc.get()); + sNvs.reset(drivers::NvsStorage::Open()); + assert(sSamd.get() && sAdc.get() && sNvs.get()); sBattery.reset(new battery::Battery(sSamd.get(), sAdc.get())); // Start bringing up LVGL now, since we have all of its prerequisites. sTrackQueue.reset(new audio::TrackQueue()); ESP_LOGI(kTag, "starting ui"); - if (!ui::UiState::Init(sGpios.get(), sTrackQueue.get(), sBattery)) { + if (!ui::UiState::Init(sGpios.get(), sNvs, sTrackQueue.get(), sBattery)) { events::System().Dispatch(FatalError{}); return; } // Install everything else that is certain to be needed. ESP_LOGI(kTag, "installing remaining drivers"); - sNvs.reset(drivers::NvsStorage::Open()); sTagParser.reset(new database::TagParserImpl()); - if (!sNvs) { - events::System().Dispatch(FatalError{}); - events::Ui().Dispatch(FatalError{}); - return; - } - // ESP_LOGI(kTag, "starting bluetooth"); // sBluetooth.reset(new drivers::Bluetooth(sNvs.get())); // sBluetooth->Enable(); diff --git a/src/ui/include/screen_settings.hpp b/src/ui/include/screen_settings.hpp index 66124164..53d9277b 100644 --- a/src/ui/include/screen_settings.hpp +++ b/src/ui/include/screen_settings.hpp @@ -6,12 +6,15 @@ #pragma once +#include #include #include +#include "display.hpp" #include "index.hpp" #include "lvgl.h" +#include "nvs.hpp" #include "screen.hpp" namespace ui { @@ -20,16 +23,6 @@ namespace screens { class Settings : public MenuScreen { public: Settings(); - ~Settings(); - - private: - std::shared_ptr bluetooth_; - std::shared_ptr headphones_; - std::shared_ptr appearance_; - std::shared_ptr input_method_; - std::shared_ptr storage_; - std::shared_ptr firmware_update_; - std::shared_ptr about_; }; class Bluetooth : public MenuScreen { @@ -44,7 +37,15 @@ class Headphones : public MenuScreen { class Appearance : public MenuScreen { public: - Appearance(); + Appearance(drivers::NvsStorage* nvs, drivers::Display* display); + + auto ChangeBrightness(uint_fast8_t) -> void; + + private: + drivers::NvsStorage* nvs_; + drivers::Display* display_; + + lv_obj_t* current_brightness_label_; }; class InputMethod : public MenuScreen { diff --git a/src/ui/include/ui_events.hpp b/src/ui/include/ui_events.hpp index 2f26c854..297370db 100644 --- a/src/ui/include/ui_events.hpp +++ b/src/ui/include/ui_events.hpp @@ -39,7 +39,16 @@ struct IndexSelected : tinyfsm::Event { struct BackPressed : tinyfsm::Event {}; struct ShowNowPlaying : tinyfsm::Event {}; struct ShowSettingsPage : tinyfsm::Event { - std::shared_ptr screen; + enum class Page { + kRoot, + kBluetooth, + kHeadphones, + kAppearance, + kInput, + kStorage, + kFirmwareUpdate, + kAbout, + } page; }; struct ModalConfirmPressed : tinyfsm::Event {}; diff --git a/src/ui/include/ui_fsm.hpp b/src/ui/include/ui_fsm.hpp index 17214e7b..1fa6bf26 100644 --- a/src/ui/include/ui_fsm.hpp +++ b/src/ui/include/ui_fsm.hpp @@ -11,6 +11,7 @@ #include "audio_events.hpp" #include "battery.hpp" +#include "nvs.hpp" #include "relative_wheel.hpp" #include "screen_playing.hpp" #include "tinyfsm.hpp" @@ -29,6 +30,7 @@ namespace ui { class UiState : public tinyfsm::Fsm { public: static auto Init(drivers::IGpios*, + std::shared_ptr, audio::TrackQueue*, std::shared_ptr) -> bool; @@ -81,6 +83,7 @@ class UiState : public tinyfsm::Fsm { static std::shared_ptr sRelativeWheel; static std::shared_ptr sDisplay; static std::shared_ptr sBattery; + static std::shared_ptr sNvs; static std::weak_ptr sDb; static std::stack> sScreens; diff --git a/src/ui/screen_menu.cpp b/src/ui/screen_menu.cpp index 7134a452..3d36c017 100644 --- a/src/ui/screen_menu.cpp +++ b/src/ui/screen_menu.cpp @@ -31,8 +31,8 @@ static void now_playing_click_cb(lv_event_t* ev) { } static void settings_click_callback(lv_event_t* ev) { - std::shared_ptr settings{new Settings()}; - events::Ui().Dispatch(internal::ShowSettingsPage{.screen = settings}); + events::Ui().Dispatch(internal::ShowSettingsPage{ + .page = internal::ShowSettingsPage::Page::kRoot}); } static void index_click_cb(lv_event_t* ev) { diff --git a/src/ui/screen_settings.cpp b/src/ui/screen_settings.cpp index 1c875700..c496ce00 100644 --- a/src/ui/screen_settings.cpp +++ b/src/ui/screen_settings.cpp @@ -8,6 +8,7 @@ #include "core/lv_event.h" #include "core/lv_obj.h" +#include "display.hpp" #include "esp_log.h" #include "core/lv_group.h" @@ -21,6 +22,7 @@ #include "index.hpp" #include "misc/lv_anim.h" #include "misc/lv_area.h" +#include "nvs.hpp" #include "screen.hpp" #include "ui_events.hpp" #include "ui_fsm.hpp" @@ -35,51 +37,43 @@ namespace ui { namespace screens { +using Page = internal::ShowSettingsPage::Page; + static void open_sub_menu_cb(lv_event_t* e) { - std::shared_ptr* next_screen = - reinterpret_cast*>(e->user_data); + Page next_page = static_cast(reinterpret_cast(e->user_data)); events::Ui().Dispatch(internal::ShowSettingsPage{ - .screen = *next_screen, + .page = next_page, }); } static void sub_menu(lv_obj_t* list, lv_group_t* group, const std::string& text, - std::shared_ptr* screen) { + Page page) { lv_obj_t* item = lv_list_add_btn(list, NULL, text.c_str()); lv_group_add_obj(group, item); - lv_obj_add_event_cb(item, open_sub_menu_cb, LV_EVENT_CLICKED, screen); + lv_obj_add_event_cb(item, open_sub_menu_cb, LV_EVENT_CLICKED, + reinterpret_cast(static_cast(page))); } -Settings::Settings() - : MenuScreen("Settings"), - bluetooth_(new Bluetooth()), - headphones_(new Headphones()), - appearance_(new Appearance()), - input_method_(new InputMethod()), - storage_(new Storage()), - firmware_update_(new FirmwareUpdate()), - about_(new About()) { +Settings::Settings() : MenuScreen("Settings") { lv_obj_t* list = lv_list_create(content_); lv_obj_set_size(list, lv_pct(100), lv_pct(100)); lv_list_add_text(list, "Audio"); - sub_menu(list, group_, "Bluetooth", &bluetooth_); - sub_menu(list, group_, "Headphones", &headphones_); + sub_menu(list, group_, "Bluetooth", Page::kBluetooth); + sub_menu(list, group_, "Headphones", Page::kBluetooth); lv_list_add_text(list, "Interface"); - sub_menu(list, group_, "Appearance", &appearance_); - sub_menu(list, group_, "Input Method", &input_method_); + sub_menu(list, group_, "Appearance", Page::kAppearance); + sub_menu(list, group_, "Input Method", Page::kInput); lv_list_add_text(list, "System"); - sub_menu(list, group_, "Storage", &storage_); - sub_menu(list, group_, "Firmware Update", &firmware_update_); - sub_menu(list, group_, "About", &about_); + sub_menu(list, group_, "Storage", Page::kStorage); + sub_menu(list, group_, "Firmware Update", Page::kFirmwareUpdate); + sub_menu(list, group_, "About", Page::kAbout); } -Settings::~Settings() {} - static auto settings_container(lv_obj_t* parent) -> lv_obj_t* { lv_obj_t* res = lv_obj_create(parent); lv_obj_set_layout(res, LV_LAYOUT_FLEX); @@ -152,13 +146,39 @@ Headphones::Headphones() : MenuScreen("Headphones") { lv_obj_set_size(current_balance_label, lv_pct(100), LV_SIZE_CONTENT); } -Appearance::Appearance() : MenuScreen("Appearance") { +static void change_brightness_cb(lv_event_t* ev) { + Appearance* instance = reinterpret_cast(ev->user_data); + instance->ChangeBrightness(lv_slider_get_value(ev->target)); +} + +Appearance::Appearance(drivers::NvsStorage* nvs, drivers::Display* display) + : MenuScreen("Appearance"), nvs_(nvs), display_(display) { lv_obj_t* toggle_container = settings_container(content_); lv_obj_t* toggle_label = lv_label_create(toggle_container); lv_obj_set_flex_grow(toggle_label, 1); lv_label_set_text(toggle_label, "Dark Mode"); lv_obj_t* toggle = lv_switch_create(toggle_container); lv_group_add_obj(group_, toggle); + + lv_obj_t* brightness_label = lv_label_create(content_); + lv_label_set_text(brightness_label, "Brightness"); + lv_obj_t* brightness = lv_slider_create(content_); + lv_obj_set_width(brightness, lv_pct(100)); + lv_slider_set_range(brightness, 10, 100); + lv_slider_set_value(brightness, 50, LV_ANIM_OFF); + lv_group_add_obj(group_, brightness); + current_brightness_label_ = lv_label_create(content_); + lv_label_set_text(current_brightness_label_, "50%"); + lv_obj_set_size(current_brightness_label_, lv_pct(100), LV_SIZE_CONTENT); + + lv_obj_add_event_cb(brightness, change_brightness_cb, LV_EVENT_VALUE_CHANGED, + this); +} + +auto Appearance::ChangeBrightness(uint_fast8_t new_level) -> void { + display_->SetBrightness(new_level); + std::string new_str = std::to_string(new_level) + "%"; + lv_label_set_text(current_brightness_label_, new_str.c_str()); } InputMethod::InputMethod() : MenuScreen("Input Method") { diff --git a/src/ui/ui_fsm.cpp b/src/ui/ui_fsm.cpp index dd3ba8fd..733b6bee 100644 --- a/src/ui/ui_fsm.cpp +++ b/src/ui/ui_fsm.cpp @@ -19,6 +19,7 @@ #include "gpios.hpp" #include "lvgl_task.hpp" #include "modal_confirm.hpp" +#include "nvs.hpp" #include "relative_wheel.hpp" #include "screen.hpp" #include "screen_menu.hpp" @@ -46,6 +47,7 @@ std::shared_ptr UiState::sTouchWheel; std::shared_ptr UiState::sRelativeWheel; std::shared_ptr UiState::sDisplay; std::shared_ptr UiState::sBattery; +std::shared_ptr UiState::sNvs; std::weak_ptr UiState::sDb; std::stack> UiState::sScreens; @@ -53,9 +55,11 @@ std::shared_ptr UiState::sCurrentScreen; std::shared_ptr UiState::sCurrentModal; auto UiState::Init(drivers::IGpios* gpio_expander, + std::shared_ptr nvs, audio::TrackQueue* queue, std::shared_ptr battery) -> bool { sIGpios = gpio_expander; + sNvs = nvs; sQueue = queue; sBattery = battery; @@ -160,7 +164,36 @@ void Browse::react(const internal::ShowNowPlaying& ev) { } void Browse::react(const internal::ShowSettingsPage& ev) { - PushScreen(ev.screen); + std::shared_ptr screen; + switch (ev.page) { + case internal::ShowSettingsPage::Page::kRoot: + screen.reset(new screens::Settings()); + break; + case internal::ShowSettingsPage::Page::kBluetooth: + screen.reset(new screens::Bluetooth()); + break; + case internal::ShowSettingsPage::Page::kHeadphones: + screen.reset(new screens::Headphones()); + break; + case internal::ShowSettingsPage::Page::kAppearance: + screen.reset(new screens::Appearance(sNvs.get(), sDisplay.get())); + break; + case internal::ShowSettingsPage::Page::kInput: + screen.reset(new screens::InputMethod()); + break; + case internal::ShowSettingsPage::Page::kStorage: + screen.reset(new screens::Storage()); + break; + case internal::ShowSettingsPage::Page::kFirmwareUpdate: + screen.reset(new screens::FirmwareUpdate()); + break; + case internal::ShowSettingsPage::Page::kAbout: + screen.reset(new screens::About()); + break; + } + if (screen) { + PushScreen(screen); + } } void Browse::react(const internal::RecordSelected& ev) {