summaryrefslogtreecommitdiff
path: root/src/ui
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui')
-rw-r--r--src/ui/include/screen.hpp5
-rw-r--r--src/ui/include/screen_lua.hpp5
-rw-r--r--src/ui/include/screen_splash.hpp2
-rw-r--r--src/ui/include/themes.hpp27
-rw-r--r--src/ui/include/ui_fsm.hpp7
-rw-r--r--src/ui/modal.cpp2
-rw-r--r--src/ui/screen.cpp5
-rw-r--r--src/ui/screen_lua.cpp60
-rw-r--r--src/ui/themes.cpp189
-rw-r--r--src/ui/ui_fsm.cpp110
10 files changed, 210 insertions, 202 deletions
diff --git a/src/ui/include/screen.hpp b/src/ui/include/screen.hpp
index 60939660..40284fda 100644
--- a/src/ui/include/screen.hpp
+++ b/src/ui/include/screen.hpp
@@ -27,6 +27,9 @@ class Screen {
Screen();
virtual ~Screen();
+ virtual auto onShown() -> void {}
+ virtual auto onHidden() -> void {}
+
auto root() -> lv_obj_t* { return root_; }
auto content() -> lv_obj_t* { return content_; }
auto alert() -> lv_obj_t* { return alert_; }
@@ -40,6 +43,8 @@ class Screen {
return group_;
}
+ virtual auto canPop() -> bool = 0;
+
protected:
lv_obj_t* const root_;
lv_obj_t* content_;
diff --git a/src/ui/include/screen_lua.hpp b/src/ui/include/screen_lua.hpp
index ee9f6813..41d97a1e 100644
--- a/src/ui/include/screen_lua.hpp
+++ b/src/ui/include/screen_lua.hpp
@@ -18,6 +18,11 @@ class Lua : public Screen {
Lua();
~Lua();
+ auto onShown() -> void override;
+ auto onHidden() -> void override;
+
+ auto canPop() -> bool override;
+
auto SetObjRef(lua_State*) -> void;
private:
diff --git a/src/ui/include/screen_splash.hpp b/src/ui/include/screen_splash.hpp
index 1ee7dd89..6e746345 100644
--- a/src/ui/include/screen_splash.hpp
+++ b/src/ui/include/screen_splash.hpp
@@ -20,6 +20,8 @@ class Splash : public Screen {
Splash();
~Splash();
+ auto canPop() -> bool override { return false; }
+
private:
lv_obj_t* container_;
lv_obj_t* label_;
diff --git a/src/ui/include/themes.hpp b/src/ui/include/themes.hpp
index 11680c0d..09b9cdce 100644
--- a/src/ui/include/themes.hpp
+++ b/src/ui/include/themes.hpp
@@ -1,5 +1,8 @@
#pragma once
+#include <string>
+#include <map>
+#include <vector>
#include "lvgl.h"
namespace ui {
@@ -19,31 +22,17 @@ class Theme {
public:
void Apply(void);
void Callback(lv_obj_t* obj);
- void ApplyStyle(lv_obj_t* obj, Style style);
+ void ApplyStyle(lv_obj_t* obj, std::string style_key);
+
+ void AddStyle(std::string key, int selector, lv_style_t* style);
static auto instance() -> Theme*;
private:
Theme();
-
- lv_style_t base_style_;
- lv_style_t base_focused_style_;
-
- lv_style_t button_style_;
- lv_style_t bar_style_;
- lv_style_t dropdown_style_;
- lv_style_t dropdown_list_style_;
-
- lv_style_t slider_indicator_style_;
- lv_style_t slider_knob_style_;
- lv_style_t slider_knob_focused_style_;
-
- lv_style_t switch_style_;
- lv_style_t switch_indicator_style_;
- lv_style_t switch_indicator_checked_style_;
- lv_style_t switch_knob_style_;
-
+ std::map<std::string, std::vector<std::pair<int, lv_style_t*>>> style_map;
lv_theme_t theme_;
+
};
} // namespace themes
} // namespace ui
diff --git a/src/ui/include/ui_fsm.hpp b/src/ui/include/ui_fsm.hpp
index 6cf2ba4c..5e1cc487 100644
--- a/src/ui/include/ui_fsm.hpp
+++ b/src/ui/include/ui_fsm.hpp
@@ -36,7 +36,7 @@ namespace ui {
class UiState : public tinyfsm::Fsm<UiState> {
public:
- static auto InitBootSplash(drivers::IGpios&) -> bool;
+ static auto InitBootSplash(drivers::IGpios&, drivers::NvsStorage&) -> bool;
virtual ~UiState() {}
@@ -57,8 +57,6 @@ class UiState : public tinyfsm::Fsm<UiState> {
virtual void react(const system_fsm::StorageMounted&) {}
void react(const system_fsm::BatteryStateChanged&);
- void react(const audio::PlaybackStarted&);
- void react(const audio::PlaybackStopped&);
void react(const audio::PlaybackUpdate&);
void react(const audio::QueueUpdate&);
@@ -129,8 +127,11 @@ class UiState : public tinyfsm::Fsm<UiState> {
static lua::Property sControlsScheme;
static lua::Property sScrollSensitivity;
+ static lua::Property sLockSwitch;
static lua::Property sDatabaseUpdating;
+
+ static lua::Property sUsbMassStorageEnabled;
};
namespace states {
diff --git a/src/ui/modal.cpp b/src/ui/modal.cpp
index 88f6d3ef..ec541914 100644
--- a/src/ui/modal.cpp
+++ b/src/ui/modal.cpp
@@ -41,8 +41,6 @@ Modal::Modal(Screen* host)
lv_obj_set_style_bg_opa(root_, LV_OPA_COVER, 0);
lv_obj_set_style_bg_color(root_, lv_color_white(), 0);
- themes::Theme::instance()->ApplyStyle(root_, themes::Style::kPopup);
-
host_->modal_group(group_);
}
diff --git a/src/ui/screen.cpp b/src/ui/screen.cpp
index 3e4f8e42..a39aaf7e 100644
--- a/src/ui/screen.cpp
+++ b/src/ui/screen.cpp
@@ -33,7 +33,10 @@ Screen::Screen()
lv_obj_center(alert_);
lv_obj_set_style_bg_opa(modal_content_, LV_OPA_TRANSP, 0);
- lv_obj_set_style_bg_color(modal_content_, lv_color_black(), 0);
+ lv_obj_set_style_bg_opa(alert_, LV_OPA_TRANSP, 0);
+
+ lv_obj_set_scrollbar_mode(root_, LV_SCROLLBAR_MODE_OFF);
+ lv_obj_set_scrollbar_mode(content_, LV_SCROLLBAR_MODE_OFF);
// Disable wrapping by default, since it's confusing and generally makes it
// harder to navigate quickly.
diff --git a/src/ui/screen_lua.cpp b/src/ui/screen_lua.cpp
index 5130b4f7..d43c7ee7 100644
--- a/src/ui/screen_lua.cpp
+++ b/src/ui/screen_lua.cpp
@@ -7,14 +7,19 @@
#include "screen_lua.hpp"
#include "core/lv_obj_tree.h"
+#include "lua.h"
#include "lua.hpp"
+#include "themes.hpp"
+#include "lua_thread.hpp"
#include "luavgl.h"
namespace ui {
namespace screens {
-Lua::Lua() : s_(nullptr), obj_ref_() {}
+Lua::Lua() : s_(nullptr), obj_ref_() {
+ themes::Theme::instance()->ApplyStyle(root_, "root");
+}
Lua::~Lua() {
if (s_ && obj_ref_) {
@@ -22,6 +27,59 @@ Lua::~Lua() {
}
}
+auto Lua::onShown() -> void {
+ if (!s_ || !obj_ref_) {
+ return;
+ }
+ lua_rawgeti(s_, LUA_REGISTRYINDEX, *obj_ref_);
+ lua_pushliteral(s_, "onShown");
+
+ if (lua_gettable(s_, -2) == LUA_TFUNCTION) {
+ lua_pushvalue(s_, -2);
+ lua::CallProtected(s_, 1, 0);
+ } else {
+ lua_pop(s_, 1);
+ }
+
+ lua_pop(s_, 1);
+}
+
+auto Lua::onHidden() -> void {
+ if (!s_ || !obj_ref_) {
+ return;
+ }
+ lua_rawgeti(s_, LUA_REGISTRYINDEX, *obj_ref_);
+ lua_pushliteral(s_, "onHidden");
+
+ if (lua_gettable(s_, -2) == LUA_TFUNCTION) {
+ lua_pushvalue(s_, -2);
+ lua::CallProtected(s_, 1, 0);
+ } else {
+ lua_pop(s_, 1);
+ }
+
+ lua_pop(s_, 1);
+}
+
+auto Lua::canPop() -> bool {
+ if (!s_ || !obj_ref_) {
+ return true;
+ }
+ lua_rawgeti(s_, LUA_REGISTRYINDEX, *obj_ref_);
+ lua_pushliteral(s_, "canPop");
+
+ if (lua_gettable(s_, -2) == LUA_TFUNCTION) {
+ // If we got a callback instead of a value, then invoke it to turn it into
+ // value.
+ lua_pushvalue(s_, -2);
+ lua::CallProtected(s_, 1, 1);
+ }
+ bool ret = lua_toboolean(s_, -1);
+
+ lua_pop(s_, 2);
+ return ret;
+}
+
auto Lua::SetObjRef(lua_State* s) -> void {
assert(s_ == nullptr);
s_ = s;
diff --git a/src/ui/themes.cpp b/src/ui/themes.cpp
index f8390570..b13f226a 100644
--- a/src/ui/themes.cpp
+++ b/src/ui/themes.cpp
@@ -19,84 +19,6 @@ static void theme_apply_cb(lv_theme_t* th, lv_obj_t* obj) {
}
Theme::Theme() {
- lv_style_init(&base_style_);
- lv_style_set_bg_opa(&base_style_, LV_OPA_TRANSP);
- lv_style_set_text_font(&base_style_, &font_fusion_12);
- lv_style_set_text_color(&base_style_, lv_color_black());
-
- lv_style_init(&base_focused_style_);
- lv_style_set_bg_opa(&base_focused_style_, LV_OPA_COVER);
- lv_style_set_bg_color(&base_focused_style_,
- lv_palette_lighten(LV_PALETTE_BLUE, 5));
-
- lv_style_init(&button_style_);
- lv_style_set_pad_left(&button_style_, 2);
- lv_style_set_pad_right(&button_style_, 2);
- lv_style_set_pad_top(&button_style_, 1);
- lv_style_set_pad_bottom(&button_style_, 1);
- lv_style_set_bg_color(&button_style_, lv_color_white());
- lv_style_set_radius(&button_style_, 5);
-
- lv_style_init(&bar_style_);
- lv_style_set_bg_opa(&bar_style_, LV_OPA_COVER);
- lv_style_set_radius(&bar_style_, LV_RADIUS_CIRCLE);
-
- lv_style_init(&slider_indicator_style_);
- lv_style_set_radius(&slider_indicator_style_, LV_RADIUS_CIRCLE);
- lv_style_set_bg_color(&slider_indicator_style_,
- lv_palette_main(LV_PALETTE_BLUE));
-
- lv_style_init(&slider_knob_style_);
- lv_style_set_radius(&slider_knob_style_, LV_RADIUS_CIRCLE);
- lv_style_set_pad_all(&slider_knob_style_, 2);
- lv_style_set_bg_color(&slider_knob_style_, lv_color_white());
- lv_style_set_shadow_width(&slider_knob_style_, 5);
- lv_style_set_shadow_opa(&slider_knob_style_, LV_OPA_COVER);
-
- lv_style_init(&slider_knob_focused_style_);
- lv_style_set_bg_color(&slider_knob_focused_style_,
- lv_palette_lighten(LV_PALETTE_BLUE, 4));
-
- lv_style_init(&switch_style_);
- lv_style_set_width(&switch_style_, 28);
- lv_style_set_height(&switch_style_, 18);
- lv_style_set_radius(&switch_style_, LV_RADIUS_CIRCLE);
-
- lv_style_init(&switch_knob_style_);
- lv_style_set_pad_all(&switch_knob_style_, -2);
- lv_style_set_radius(&switch_knob_style_, LV_RADIUS_CIRCLE);
- lv_style_set_bg_opa(&switch_knob_style_, LV_OPA_COVER);
- lv_style_set_bg_color(&switch_knob_style_, lv_color_white());
-
- lv_style_init(&slider_knob_focused_style_);
- lv_style_set_bg_color(&slider_knob_focused_style_,
- lv_palette_lighten(LV_PALETTE_BLUE, 4));
-
- lv_style_init(&switch_indicator_style_);
- lv_style_set_radius(&switch_indicator_style_, LV_RADIUS_CIRCLE);
- lv_style_set_bg_opa(&switch_indicator_style_, LV_OPA_COVER);
- lv_style_set_bg_color(&switch_indicator_style_,
- lv_palette_main(LV_PALETTE_GREY));
-
- lv_style_init(&switch_indicator_checked_style_);
- lv_style_set_bg_color(&switch_indicator_checked_style_,
- lv_palette_main(LV_PALETTE_BLUE));
-
- lv_style_init(&dropdown_style_);
- lv_style_set_radius(&dropdown_style_, 2);
- lv_style_set_pad_all(&dropdown_style_, 2);
- lv_style_set_border_width(&dropdown_style_, 1);
- lv_style_set_border_color(&dropdown_style_, lv_palette_main(LV_PALETTE_BLUE));
- lv_style_set_border_side(&dropdown_style_, LV_BORDER_SIDE_FULL);
-
- lv_style_init(&dropdown_list_style_);
- lv_style_set_radius(&dropdown_list_style_, 2);
- lv_style_set_border_width(&dropdown_list_style_, 1);
- lv_style_set_border_color(&dropdown_list_style_, lv_palette_main(LV_PALETTE_BLUE_GREY));
- lv_style_set_bg_opa(&dropdown_list_style_, LV_OPA_COVER);
- lv_style_set_bg_color(&dropdown_list_style_, lv_color_white());
- lv_style_set_pad_all(&dropdown_list_style_, 2);
-
lv_theme_t* parent_theme = lv_disp_get_theme(NULL);
theme_ = *parent_theme;
theme_.user_data = this;
@@ -111,91 +33,46 @@ void Theme::Apply(void) {
}
void Theme::Callback(lv_obj_t* obj) {
- lv_obj_add_style(obj, &base_style_, LV_PART_MAIN);
- lv_obj_add_style(obj, &base_focused_style_, LV_PART_SELECTED);
- lv_obj_add_style(obj, &base_focused_style_, LV_STATE_FOCUSED);
+ // Find and apply base styles
+ if (auto search = style_map.find("base"); search != style_map.end()) {
+ for (const auto& pair : search->second) {
+ lv_obj_add_style(obj, pair.second, pair.first);
+ }
+ }
+ // Determine class name
+ std::string class_name;
if (lv_obj_check_type(obj, &lv_btn_class)) {
- lv_obj_add_style(obj, &button_style_, LV_PART_MAIN);
+ class_name = "button";
+ } else if (lv_obj_check_type(obj, &lv_list_btn_class)) {
+ class_name = "listbutton";
} else if (lv_obj_check_type(obj, &lv_bar_class)) {
- lv_obj_add_style(obj, &bar_style_, LV_PART_MAIN);
+ class_name = "bar";
} else if (lv_obj_check_type(obj, &lv_slider_class)) {
- lv_obj_add_style(obj, &bar_style_, LV_PART_MAIN);
- lv_obj_add_style(obj, &slider_indicator_style_, LV_PART_INDICATOR);
- lv_obj_add_style(obj, &slider_knob_style_, LV_PART_KNOB);
- lv_obj_add_style(obj, &slider_knob_focused_style_, LV_STATE_FOCUSED);
+ class_name = "slider";
} else if (lv_obj_check_type(obj, &lv_switch_class)) {
- lv_obj_add_style(obj, &switch_style_, LV_PART_MAIN);
- lv_obj_add_style(obj, &switch_indicator_style_, LV_PART_INDICATOR);
- lv_obj_add_style(obj, &switch_indicator_checked_style_,
- LV_PART_INDICATOR | LV_STATE_CHECKED);
- lv_obj_add_style(obj, &switch_knob_style_, LV_PART_KNOB);
+ class_name = "switch";
} else if (lv_obj_check_type(obj, &lv_dropdown_class)) {
- lv_obj_add_style(obj, &dropdown_style_, LV_PART_MAIN);
+ class_name = "dropdown";
} else if (lv_obj_check_type(obj, &lv_dropdownlist_class)) {
- lv_obj_add_style(obj, &dropdown_list_style_, LV_PART_MAIN);
+ class_name = "dropdownlist";
}
-}
-
-void Theme::ApplyStyle(lv_obj_t* obj, Style style) {
- switch (style) {
- case Style::kTopBar:
- lv_obj_set_style_pad_bottom(obj, 1, LV_PART_MAIN);
-
- lv_obj_set_style_shadow_width(obj, 6, LV_PART_MAIN);
- lv_obj_set_style_shadow_opa(obj, LV_OPA_COVER, LV_PART_MAIN);
- lv_obj_set_style_shadow_ofs_x(obj, 0, LV_PART_MAIN);
- break;
- case Style::kPopup:
- lv_obj_set_style_shadow_width(obj, 6, LV_PART_MAIN);
- lv_obj_set_style_shadow_opa(obj, LV_OPA_COVER, LV_PART_MAIN);
- lv_obj_set_style_shadow_ofs_x(obj, 0, LV_PART_MAIN);
- lv_obj_set_style_shadow_ofs_y(obj, 0, LV_PART_MAIN);
-
- lv_obj_set_style_radius(obj, 5, LV_PART_MAIN);
-
- lv_obj_set_style_bg_opa(obj, LV_OPA_COVER, LV_PART_MAIN);
- lv_obj_set_style_bg_color(obj, lv_color_white(), LV_PART_MAIN);
- lv_obj_set_style_pad_top(obj, 2, LV_PART_MAIN);
- lv_obj_set_style_pad_bottom(obj, 2, LV_PART_MAIN);
- lv_obj_set_style_pad_left(obj, 2, LV_PART_MAIN);
- lv_obj_set_style_pad_right(obj, 2, LV_PART_MAIN);
- break;
- case Style::kTab:
- lv_obj_set_style_radius(obj, 0, LV_PART_MAIN);
-
- lv_obj_set_style_border_width(obj, 1, LV_STATE_CHECKED);
- lv_obj_set_style_border_color(obj, lv_palette_main(LV_PALETTE_BLUE),
- LV_STATE_CHECKED);
- lv_obj_set_style_border_side(obj, LV_BORDER_SIDE_BOTTOM,
- LV_STATE_CHECKED);
- break;
- case Style::kButtonPrimary:
- lv_obj_set_style_border_width(obj, 1, LV_PART_MAIN);
- lv_obj_set_style_border_color(obj, lv_palette_main(LV_PALETTE_BLUE),
- LV_PART_MAIN);
- lv_obj_set_style_border_side(obj, LV_BORDER_SIDE_FULL, LV_PART_MAIN);
- break;
- case Style::kMenuSubheadFirst:
- case Style::kMenuSubhead:
- lv_obj_set_style_text_color(obj, lv_palette_darken(LV_PALETTE_GREY, 3),
- LV_PART_MAIN);
- lv_obj_set_style_text_align(obj, LV_TEXT_ALIGN_CENTER, LV_PART_MAIN);
+ // Apply all styles from class
+ if (auto search = style_map.find(class_name); search != style_map.end()) {
+ for (const auto& pair : search->second) {
+ lv_obj_add_style(obj, pair.second, pair.first);
+ }
+ }
- lv_obj_set_style_border_width(obj, 1, LV_PART_MAIN);
- lv_obj_set_style_border_color(obj, lv_palette_lighten(LV_PALETTE_GREY, 3),
- LV_PART_MAIN);
+}
- if (style == Style::kMenuSubhead) {
- lv_obj_set_style_border_side(
- obj, LV_BORDER_SIDE_TOP | LV_BORDER_SIDE_BOTTOM, LV_PART_MAIN);
- } else {
- lv_obj_set_style_border_side(obj, LV_BORDER_SIDE_BOTTOM, LV_PART_MAIN);
+void Theme::ApplyStyle(lv_obj_t* obj, std::string style_key) {
+ if (auto search = style_map.find(style_key); search != style_map.end()) {
+ for (const auto& pair : search->second) {
+ lv_obj_remove_style(obj, pair.second, pair.first);
+ lv_obj_add_style(obj, pair.second, pair.first);
}
- break;
- default:
- break;
}
}
@@ -204,5 +81,15 @@ auto Theme::instance() -> Theme* {
return &sTheme;
}
+void Theme::AddStyle(std::string key, int selector, lv_style_t* style) {
+ style_map.try_emplace(key, std::vector<std::pair<int, lv_style_t*>>{});
+ if (auto search = style_map.find(key); search != style_map.end()) {
+ // Key exists
+ auto &vec = search->second;
+ // Add it to the list
+ vec.push_back(std::make_pair(selector, style));
+ }
+}
+
} // namespace themes
} // namespace ui
diff --git a/src/ui/ui_fsm.cpp b/src/ui/ui_fsm.cpp
index f5288882..835da19e 100644
--- a/src/ui/ui_fsm.cpp
+++ b/src/ui/ui_fsm.cpp
@@ -12,6 +12,7 @@
#include "bluetooth_types.hpp"
#include "db_events.hpp"
+#include "display_init.hpp"
#include "freertos/portmacro.h"
#include "freertos/projdefs.h"
#include "lua.h"
@@ -113,19 +114,34 @@ lua::Property UiState::sBluetoothDevices{
lua::Property UiState::sPlaybackPlaying{
false, [](const lua::LuaValue& val) {
- bool current_val = std::get<bool>(sPlaybackPlaying.Get());
if (!std::holds_alternative<bool>(val)) {
return false;
}
bool new_val = std::get<bool>(val);
- if (current_val != new_val) {
- events::Audio().Dispatch(audio::TogglePlayPause{});
- }
+ events::Audio().Dispatch(audio::TogglePlayPause{.set_to = new_val});
return true;
}};
lua::Property UiState::sPlaybackTrack{};
-lua::Property UiState::sPlaybackPosition{0};
+lua::Property UiState::sPlaybackPosition{
+ 0, [](const lua::LuaValue& val) {
+ int current_val = std::get<int>(sPlaybackPosition.Get());
+ if (!std::holds_alternative<int>(val)) {
+ return false;
+ }
+ int new_val = std::get<int>(val);
+ if (current_val != new_val) {
+ auto track = sPlaybackTrack.Get();
+ if (!std::holds_alternative<audio::TrackInfo>(track)) {
+ return false;
+ }
+ events::Audio().Dispatch(audio::SetTrack{
+ .new_track = std::get<audio::TrackInfo>(track).uri,
+ .seek_to_second = (uint32_t)new_val,
+ });
+ }
+ return true;
+ }};
lua::Property UiState::sQueuePosition{0};
lua::Property UiState::sQueueSize{0};
@@ -263,12 +279,36 @@ lua::Property UiState::sScrollSensitivity{
return true;
}};
+lua::Property UiState::sLockSwitch{false};
+
lua::Property UiState::sDatabaseUpdating{false};
-auto UiState::InitBootSplash(drivers::IGpios& gpios) -> bool {
+lua::Property UiState::sUsbMassStorageEnabled{
+ false, [](const lua::LuaValue& val) {
+ if (!std::holds_alternative<bool>(val)) {
+ return false;
+ }
+ bool enable = std::get<bool>(val);
+ // FIXME: Check for system busy.
+ events::System().Dispatch(system_fsm::SamdUsbMscChanged{.en = enable});
+ return true;
+ }};
+
+auto UiState::InitBootSplash(drivers::IGpios& gpios, drivers::NvsStorage& nvs)
+ -> bool {
// Init LVGL first, since the display driver registers itself with LVGL.
lv_init();
- sDisplay.reset(drivers::Display::Create(gpios, drivers::displays::kST7735R));
+
+ drivers::displays::InitialisationData init_data = drivers::displays::kST7735R;
+
+ // HACK: correct the display size for our prototypes.
+ // nvs.DisplaySize({161, 130});
+
+ auto actual_size = nvs.DisplaySize();
+ init_data.width = actual_size.first.value_or(init_data.width);
+ init_data.height = actual_size.second.value_or(init_data.height);
+
+ sDisplay.reset(drivers::Display::Create(gpios, init_data));
if (sDisplay == nullptr) {
return false;
}
@@ -280,27 +320,36 @@ auto UiState::InitBootSplash(drivers::IGpios& gpios) -> bool {
}
void UiState::PushScreen(std::shared_ptr<Screen> screen) {
+ lv_obj_set_parent(sAlertContainer, screen->alert());
+
if (sCurrentScreen) {
+ sCurrentScreen->onHidden();
sScreens.push(sCurrentScreen);
}
sCurrentScreen = screen;
- lv_obj_set_parent(sAlertContainer, sCurrentScreen->alert());
+ sCurrentScreen->onShown();
}
int UiState::PopScreen() {
if (sScreens.empty()) {
return 0;
}
- sCurrentScreen = sScreens.top();
- lv_obj_set_parent(sAlertContainer, sCurrentScreen->alert());
+ lv_obj_set_parent(sAlertContainer, sScreens.top()->alert());
+
+ sCurrentScreen->onHidden();
+ sCurrentScreen = sScreens.top();
sScreens.pop();
+
+ sCurrentScreen->onShown();
+
return sScreens.size();
}
void UiState::react(const system_fsm::KeyLockChanged& ev) {
sDisplay->SetDisplayOn(!ev.locking);
sInput->lock(ev.locking);
+ sLockSwitch.Update(ev.locking);
}
void UiState::react(const internal::ControlSchemeChanged&) {
@@ -342,17 +391,14 @@ void UiState::react(const audio::QueueUpdate&) {
sQueueReplay.Update(queue.replay());
}
-void UiState::react(const audio::PlaybackStarted& ev) {
- sPlaybackPlaying.Update(true);
-}
-
void UiState::react(const audio::PlaybackUpdate& ev) {
- sPlaybackTrack.Update(*ev.track);
- sPlaybackPosition.Update(static_cast<int>(ev.seconds_elapsed));
-}
-
-void UiState::react(const audio::PlaybackStopped&) {
- sPlaybackPlaying.Update(false);
+ if (ev.current_track) {
+ sPlaybackTrack.Update(*ev.current_track);
+ } else {
+ sPlaybackTrack.Update(std::monostate{});
+ }
+ sPlaybackPlaying.Update(!ev.paused);
+ sPlaybackPosition.Update(static_cast<int>(ev.track_position.value_or(0)));
}
void UiState::react(const audio::VolumeChanged& ev) {
@@ -443,6 +489,7 @@ void Lua::entry() {
sAlertTimer = xTimerCreate("ui_alerts", pdMS_TO_TICKS(1000), false, NULL,
alert_timer_callback);
sAlertContainer = lv_obj_create(sCurrentScreen->alert());
+ lv_obj_set_style_bg_opa(sAlertContainer, LV_OPA_TRANSP, 0);
auto& registry = lua::Registry::instance(*sServices);
sLua = registry.uiThread();
@@ -491,6 +538,7 @@ void Lua::entry() {
{
{"scheme", &sControlsScheme},
{"scroll_sensitivity", &sScrollSensitivity},
+ {"lock_switch", &sLockSwitch},
});
registry.AddPropertyModule(
@@ -512,6 +560,10 @@ void Lua::entry() {
registry.AddPropertyModule("database", {
{"updating", &sDatabaseUpdating},
});
+ registry.AddPropertyModule("usb",
+ {
+ {"msc_enabled", &sUsbMassStorageEnabled},
+ });
auto bt = sServices->bluetooth();
sBluetoothEnabled.Update(bt.IsEnabled());
@@ -525,7 +577,7 @@ void Lua::entry() {
auto Lua::PushLuaScreen(lua_State* s) -> int {
// Ensure the arg looks right before continuing.
- luaL_checktype(s, 1, LUA_TFUNCTION);
+ luaL_checktype(s, 1, LUA_TTABLE);
// First, create a new plain old Screen object. We will use its root and
// group for the Lua screen. Allocate it in external ram so that arbitrarily
@@ -540,10 +592,15 @@ auto Lua::PushLuaScreen(lua_State* s) -> int {
lv_group_set_default(new_screen->group());
// Call the constructor for this screen.
- lua_settop(s, 1); // Make sure the function is actually at top of stack
- lua::CallProtected(s, 0, 1);
+ // lua_settop(s, 1); // Make sure the screen is actually at top of stack
+ lua_pushliteral(s, "createUi");
+ if (lua_gettable(s, 1) == LUA_TFUNCTION) {
+ lua_pushvalue(s, 1);
+ lua::CallProtected(s, 1, 0);
+ }
- // Store the reference for the table the constructor returned.
+ // Store the reference for this screen's table.
+ lua_settop(s, 1);
new_screen->SetObjRef(s);
// Finally, push the now-initialised screen as if it were a regular C++
@@ -564,6 +621,9 @@ auto Lua::QueuePrevious(lua_State*) -> int {
}
auto Lua::PopLuaScreen(lua_State* s) -> int {
+ if (!sCurrentScreen->canPop()) {
+ return 0;
+ }
PopScreen();
luavgl_set_root(s, sCurrentScreen->content());
lv_group_set_default(sCurrentScreen->group());
@@ -571,7 +631,7 @@ auto Lua::PopLuaScreen(lua_State* s) -> int {
}
auto Lua::Ticks(lua_State* s) -> int {
- lua_pushinteger(s, esp_timer_get_time()/1000);
+ lua_pushinteger(s, esp_timer_get_time() / 1000);
return 1;
}