summaryrefslogtreecommitdiff
path: root/src/ui
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui')
-rw-r--r--src/ui/include/screen.hpp2
-rw-r--r--src/ui/include/ui_events.hpp8
-rw-r--r--src/ui/include/ui_fsm.hpp11
-rw-r--r--src/ui/screen.cpp4
-rw-r--r--src/ui/ui_fsm.cpp72
5 files changed, 94 insertions, 3 deletions
diff --git a/src/ui/include/screen.hpp b/src/ui/include/screen.hpp
index e9eaeeb0..4fe0a3b7 100644
--- a/src/ui/include/screen.hpp
+++ b/src/ui/include/screen.hpp
@@ -40,6 +40,7 @@ class Screen {
auto root() -> lv_obj_t* { return root_; }
auto content() -> lv_obj_t* { return content_; }
+ auto alert() -> lv_obj_t* { return alert_; }
auto modal_content() -> lv_obj_t* { return modal_content_; }
auto modal_group(lv_group_t* g) -> void { modal_group_ = g; }
@@ -68,6 +69,7 @@ class Screen {
lv_obj_t* const root_;
lv_obj_t* content_;
lv_obj_t* modal_content_;
+ lv_obj_t* alert_;
lv_group_t* const group_;
lv_group_t* modal_group_;
diff --git a/src/ui/include/ui_events.hpp b/src/ui/include/ui_events.hpp
index 111f37a8..59be7606 100644
--- a/src/ui/include/ui_events.hpp
+++ b/src/ui/include/ui_events.hpp
@@ -24,9 +24,9 @@ struct OnStorageChange : tinyfsm::Event {
struct OnSystemError : tinyfsm::Event {};
- struct OnLuaError : tinyfsm::Event {
- std::string message;
- };
+struct OnLuaError : tinyfsm::Event {
+ std::string message;
+};
namespace internal {
@@ -54,6 +54,8 @@ struct OnboardingNavigate : tinyfsm::Event {
struct ModalConfirmPressed : tinyfsm::Event {};
struct ModalCancelPressed : tinyfsm::Event {};
+struct DismissAlerts : tinyfsm::Event {};
+
} // namespace internal
} // namespace ui
diff --git a/src/ui/include/ui_fsm.hpp b/src/ui/include/ui_fsm.hpp
index ba3f5e3f..33f9eac4 100644
--- a/src/ui/include/ui_fsm.hpp
+++ b/src/ui/include/ui_fsm.hpp
@@ -60,6 +60,7 @@ class UiState : public tinyfsm::Fsm<UiState> {
virtual void react(const audio::PlaybackFinished&);
virtual void react(const audio::PlaybackUpdate&);
virtual void react(const audio::QueueUpdate&);
+ virtual void react(const audio::VolumeChanged&){};
virtual void react(const system_fsm::KeyLockChanged&);
virtual void react(const OnLuaError&) {}
@@ -76,6 +77,8 @@ class UiState : public tinyfsm::Fsm<UiState> {
void react(const internal::ControlSchemeChanged&);
virtual void react(const internal::ReindexDatabase&){};
+ void react(const internal::DismissAlerts&);
+
virtual void react(const database::event::UpdateStarted&){};
virtual void react(const database::event::UpdateProgress&){};
virtual void react(const database::event::UpdateFinished&){};
@@ -129,6 +132,7 @@ class Lua : public UiState {
void react(const audio::PlaybackStarted&) override;
void react(const audio::PlaybackUpdate&) override;
void react(const audio::PlaybackFinished&) override;
+ void react(const audio::VolumeChanged&) override;
void react(const internal::BackPressed&) override;
using UiState::react;
@@ -136,6 +140,10 @@ class Lua : public UiState {
private:
auto PushLuaScreen(lua_State*) -> int;
auto PopLuaScreen(lua_State*) -> int;
+
+ auto ShowAlert(lua_State*) -> int;
+ auto HideAlert(lua_State*) -> int;
+
auto SetPlaying(const lua::LuaValue&) -> bool;
auto SetRandom(const lua::LuaValue&) -> bool;
auto SetRepeat(const lua::LuaValue&) -> bool;
@@ -154,6 +162,9 @@ class Lua : public UiState {
std::shared_ptr<lua::Property> queue_size_;
std::shared_ptr<lua::Property> queue_repeat_;
std::shared_ptr<lua::Property> queue_random_;
+
+ std::shared_ptr<lua::Property> volume_current_pct_;
+ std::shared_ptr<lua::Property> volume_current_db_;
};
class Browse : public UiState {
diff --git a/src/ui/screen.cpp b/src/ui/screen.cpp
index 0b0f7914..9ac5ec0e 100644
--- a/src/ui/screen.cpp
+++ b/src/ui/screen.cpp
@@ -10,6 +10,7 @@
#include "core/lv_obj_pos.h"
#include "core/lv_obj_tree.h"
+#include "hal/lv_hal_disp.h"
#include "misc/lv_area.h"
#include "misc/lv_color.h"
#include "model_top_bar.hpp"
@@ -21,14 +22,17 @@ Screen::Screen()
: root_(lv_obj_create(NULL)),
content_(lv_obj_create(root_)),
modal_content_(lv_obj_create(root_)),
+ alert_(lv_obj_create(root_)),
group_(lv_group_create()),
modal_group_(nullptr) {
lv_obj_set_size(root_, lv_pct(100), lv_pct(100));
lv_obj_set_size(content_, lv_pct(100), lv_pct(100));
lv_obj_set_size(modal_content_, lv_pct(100), lv_pct(100));
+ lv_obj_set_size(alert_, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
lv_obj_center(root_);
lv_obj_center(content_);
lv_obj_center(modal_content_);
+ 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);
diff --git a/src/ui/ui_fsm.cpp b/src/ui/ui_fsm.cpp
index 8e355fd1..740383a4 100644
--- a/src/ui/ui_fsm.cpp
+++ b/src/ui/ui_fsm.cpp
@@ -9,6 +9,8 @@
#include <memory>
#include <variant>
+#include "freertos/portmacro.h"
+#include "freertos/projdefs.h"
#include "lua.h"
#include "lua.hpp"
@@ -44,6 +46,7 @@
#include "spiffs.hpp"
#include "storage.hpp"
#include "system_events.hpp"
+#include "tinyfsm.hpp"
#include "touchwheel.hpp"
#include "track_queue.hpp"
#include "ui_events.hpp"
@@ -70,6 +73,13 @@ models::TopBar UiState::sTopBarModel{{},
UiState::sPlaybackModel.is_playing,
UiState::sPlaybackModel.current_track};
+static TimerHandle_t sAlertTimer;
+static lv_obj_t* sAlertContainer;
+
+static void alert_timer_callback(TimerHandle_t timer) {
+ events::Ui().Dispatch(internal::DismissAlerts{});
+}
+
auto UiState::InitBootSplash(drivers::IGpios& gpios) -> bool {
// Init LVGL first, since the display driver registers itself with LVGL.
lv_init();
@@ -89,6 +99,7 @@ void UiState::PushScreen(std::shared_ptr<Screen> screen) {
sScreens.push(sCurrentScreen);
}
sCurrentScreen = screen;
+ lv_obj_set_parent(sAlertContainer, sCurrentScreen->alert());
}
int UiState::PopScreen() {
@@ -96,6 +107,8 @@ int UiState::PopScreen() {
return 0;
}
sCurrentScreen = sScreens.top();
+ lv_obj_set_parent(sAlertContainer, sCurrentScreen->alert());
+
sScreens.pop();
return sScreens.size();
}
@@ -127,6 +140,10 @@ void UiState::react(const internal::ControlSchemeChanged&) {
sInput->mode(sServices->nvs().PrimaryInput());
}
+void UiState::react(const internal::DismissAlerts&) {
+ lv_obj_clean(sAlertContainer);
+}
+
namespace states {
void Splash::exit() {
@@ -164,6 +181,10 @@ void Splash::react(const system_fsm::StorageMounted&) {
void Lua::entry() {
if (!sLua) {
+ sAlertTimer = xTimerCreate("ui_alerts", pdMS_TO_TICKS(1000), false, NULL,
+ alert_timer_callback);
+ sAlertContainer = lv_obj_create(sCurrentScreen->alert());
+
auto bat =
sServices->battery().State().value_or(battery::Battery::BatteryState{});
battery_pct_ =
@@ -184,6 +205,9 @@ void Lua::entry() {
playback_track_ = std::make_shared<lua::Property>();
playback_position_ = std::make_shared<lua::Property>();
+ volume_current_pct_ = std::make_shared<lua::Property>(0);
+ volume_current_db_ = std::make_shared<lua::Property>(0);
+
sLua.reset(lua::LuaThread::Start(*sServices, sCurrentScreen->content()));
sLua->bridge().AddPropertyModule("power",
{
@@ -208,12 +232,23 @@ void Lua::entry() {
{"replay", queue_repeat_},
{"random", queue_random_},
});
+ sLua->bridge().AddPropertyModule("volume",
+ {
+ {"current_pct", volume_current_pct_},
+ {"current_db", volume_current_db_},
+ });
+
sLua->bridge().AddPropertyModule(
"backstack",
{
{"push", [&](lua_State* s) { return PushLuaScreen(s); }},
{"pop", [&](lua_State* s) { return PopLuaScreen(s); }},
});
+ sLua->bridge().AddPropertyModule(
+ "alerts", {
+ {"show", [&](lua_State* s) { return ShowAlert(s); }},
+ {"hide", [&](lua_State* s) { return HideAlert(s); }},
+ });
sCurrentScreen.reset();
sLua->RunScript("/lua/main.lua");
@@ -265,6 +300,38 @@ auto Lua::SetPlaying(const lua::LuaValue& val) -> bool {
return true;
}
+auto Lua::ShowAlert(lua_State* s) -> int {
+ if (!sCurrentScreen) {
+ return 0;
+ }
+ xTimerReset(sAlertTimer, portMAX_DELAY);
+ tinyfsm::FsmList<UiState>::dispatch(internal::DismissAlerts{});
+
+ lv_group_t* prev_group = lv_group_get_default();
+
+ luavgl_set_root(s, sAlertContainer);
+ lv_group_t* catchall = lv_group_create();
+ lv_group_set_default(catchall);
+
+ // Call the constructor for the alert.
+ lua_settop(s, 1); // Make sure the function is actually at top of stack
+ lua::CallProtected(s, 0, 1);
+
+ // Restore the previous group and default object.
+ luavgl_set_root(s, sCurrentScreen->content());
+ lv_group_set_default(prev_group);
+
+ lv_group_del(catchall);
+
+ return 0;
+}
+
+auto Lua::HideAlert(lua_State* s) -> int {
+ xTimerStop(sAlertTimer, portMAX_DELAY);
+ tinyfsm::FsmList<UiState>::dispatch(internal::DismissAlerts{});
+ return 0;
+}
+
auto Lua::SetRandom(const lua::LuaValue& val) -> bool {
if (!std::holds_alternative<bool>(val)) {
return false;
@@ -327,6 +394,11 @@ void Lua::react(const audio::PlaybackFinished&) {
playback_playing_->Update(false);
}
+void Lua::react(const audio::VolumeChanged& ev) {
+ volume_current_pct_->Update(static_cast<int>(ev.percent));
+ volume_current_db_->Update(static_cast<int>(ev.db));
+}
+
void Lua::react(const internal::BackPressed& ev) {
PopLuaScreen(sLua->state());
}