summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2023-08-25 10:13:37 +1000
committerjacqueline <me@jacqueline.id.au>2023-08-25 10:13:37 +1000
commit3b3bc64d19715c418f407d5231795ca5a2c2fa71 (patch)
tree87fb1bf2b9ec366abc712f2096a0908d0ae2cc4b /src
parent079b2b53d434869df419da1373aba239990c34d9 (diff)
downloadtangara-fw-3b3bc64d19715c418f407d5231795ca5a2c2fa71.tar.gz
Add modal dialog support
Diffstat (limited to 'src')
-rw-r--r--src/drivers/touchwheel.cpp1
-rw-r--r--src/ui/CMakeLists.txt1
-rw-r--r--src/ui/include/modal.hpp37
-rw-r--r--src/ui/include/modal_confirm.hpp29
-rw-r--r--src/ui/include/modal_progress.hpp29
-rw-r--r--src/ui/include/screen.hpp26
-rw-r--r--src/ui/include/ui_events.hpp3
-rw-r--r--src/ui/include/ui_fsm.hpp11
-rw-r--r--src/ui/lvgl_task.cpp7
-rw-r--r--src/ui/modal.cpp57
-rw-r--r--src/ui/modal_confirm.cpp74
-rw-r--r--src/ui/modal_progress.cpp46
-rw-r--r--src/ui/screen.cpp28
-rw-r--r--src/ui/screen_menu.cpp10
-rw-r--r--src/ui/screen_playing.cpp20
-rw-r--r--src/ui/screen_track_browser.cpp13
-rw-r--r--src/ui/ui_fsm.cpp26
17 files changed, 385 insertions, 33 deletions
diff --git a/src/drivers/touchwheel.cpp b/src/drivers/touchwheel.cpp
index 14cfa689..836e688a 100644
--- a/src/drivers/touchwheel.cpp
+++ b/src/drivers/touchwheel.cpp
@@ -59,7 +59,6 @@ TouchWheel::TouchWheel() {
for (int i = 5; i < 12; i++) {
WriteRegister(Register::KEY_CONTROL_BASE + i, 1);
}
-
}
TouchWheel::~TouchWheel() {}
diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt
index f17020ac..06bad37e 100644
--- a/src/ui/CMakeLists.txt
+++ b/src/ui/CMakeLists.txt
@@ -6,6 +6,7 @@ idf_component_register(
SRCS "lvgl_task.cpp" "ui_fsm.cpp" "screen_splash.cpp" "screen_menu.cpp"
"wheel_encoder.cpp" "screen_track_browser.cpp" "screen_playing.cpp"
"themes.cpp" "widget_top_bar.cpp" "screen.cpp" "screen_onboarding.cpp"
+ "modal_progress.cpp" "modal.cpp" "modal_confirm.cpp"
"splash.c" "font_fusion.c" "font_symbols.c"
INCLUDE_DIRS "include"
REQUIRES "drivers" "lvgl" "tinyfsm" "events" "system_fsm" "database" "esp_timer")
diff --git a/src/ui/include/modal.hpp b/src/ui/include/modal.hpp
new file mode 100644
index 00000000..a5ac69b8
--- /dev/null
+++ b/src/ui/include/modal.hpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2023 jacqueline <me@jacqueline.id.au>
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#pragma once
+
+#include <memory>
+
+#include "core/lv_group.h"
+#include "core/lv_obj.h"
+#include "core/lv_obj_tree.h"
+#include "lvgl.h"
+#include "widget_top_bar.hpp"
+
+#include "screen.hpp"
+
+namespace ui {
+
+class Modal {
+ public:
+ Modal(Screen* host);
+ virtual ~Modal();
+
+ auto root() -> lv_obj_t* { return root_; }
+ auto group() -> lv_group_t* { return group_; }
+
+ protected:
+ lv_obj_t* const root_;
+ lv_group_t* const group_;
+
+ private:
+ Screen* host_;
+};
+
+} // namespace ui
diff --git a/src/ui/include/modal_confirm.hpp b/src/ui/include/modal_confirm.hpp
new file mode 100644
index 00000000..4be6b68e
--- /dev/null
+++ b/src/ui/include/modal_confirm.hpp
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2023 jacqueline <me@jacqueline.id.au>
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#pragma once
+
+#include <memory>
+#include <vector>
+
+#include "index.hpp"
+#include "lvgl.h"
+
+#include "modal.hpp"
+
+namespace ui {
+namespace modals {
+
+class Confirm : public Modal {
+ public:
+ Confirm(Screen*, const std::string& title, bool has_cancel);
+
+ private:
+ lv_obj_t* container_;
+};
+
+} // namespace modals
+} // namespace ui
diff --git a/src/ui/include/modal_progress.hpp b/src/ui/include/modal_progress.hpp
new file mode 100644
index 00000000..96897029
--- /dev/null
+++ b/src/ui/include/modal_progress.hpp
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2023 jacqueline <me@jacqueline.id.au>
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#pragma once
+
+#include <memory>
+#include <vector>
+
+#include "index.hpp"
+#include "lvgl.h"
+
+#include "modal.hpp"
+
+namespace ui {
+namespace modals {
+
+class Progress : public Modal {
+ public:
+ Progress(Screen*, std::string title);
+
+ private:
+ lv_obj_t* container_;
+};
+
+} // namespace modals
+} // namespace ui
diff --git a/src/ui/include/screen.hpp b/src/ui/include/screen.hpp
index 0ec72a63..250b3c8d 100644
--- a/src/ui/include/screen.hpp
+++ b/src/ui/include/screen.hpp
@@ -7,6 +7,7 @@
#pragma once
#include <memory>
+#include <optional>
#include "core/lv_group.h"
#include "core/lv_obj.h"
@@ -23,14 +24,8 @@ namespace ui {
*/
class Screen {
public:
- Screen() : root_(lv_obj_create(NULL)), group_(lv_group_create()) {}
-
- virtual ~Screen() {
- // The group *must* be deleted first. Otherwise, focus events will be
- // generated whilst deleting the object tree, which causes a big mess.
- lv_group_del(group_);
- lv_obj_del(root_);
- }
+ Screen();
+ virtual ~Screen();
/*
* Called periodically to allow the screen to update itself, e.g. to handle
@@ -41,14 +36,27 @@ class Screen {
auto UpdateTopBar(const widgets::TopBar::State& state) -> void;
auto root() -> lv_obj_t* { return root_; }
- auto group() -> lv_group_t* { return group_; }
+ auto content() -> lv_obj_t* { return content_; }
+
+ auto modal_content() -> lv_obj_t* { return modal_content_; }
+ auto modal_group(lv_group_t* g) -> void { modal_group_ = g; }
+ auto group() -> lv_group_t* {
+ if (modal_group_) {
+ return modal_group_;
+ }
+ return group_;
+ }
protected:
auto CreateTopBar(lv_obj_t* parent, const widgets::TopBar::Configuration&)
-> widgets::TopBar*;
lv_obj_t* const root_;
+ lv_obj_t* const content_;
+ lv_obj_t* const modal_content_;
+
lv_group_t* const group_;
+ lv_group_t* modal_group_;
private:
std::unique_ptr<widgets::TopBar> top_bar_;
diff --git a/src/ui/include/ui_events.hpp b/src/ui/include/ui_events.hpp
index a0ef1c31..759a0879 100644
--- a/src/ui/include/ui_events.hpp
+++ b/src/ui/include/ui_events.hpp
@@ -37,6 +37,9 @@ struct IndexSelected : tinyfsm::Event {
struct BackPressed : tinyfsm::Event {};
+struct ModalConfirmPressed : tinyfsm::Event {};
+struct ModalCancelPressed : tinyfsm::Event {};
+
} // namespace internal
} // namespace ui
diff --git a/src/ui/include/ui_fsm.hpp b/src/ui/include/ui_fsm.hpp
index 1551932a..4985129a 100644
--- a/src/ui/include/ui_fsm.hpp
+++ b/src/ui/include/ui_fsm.hpp
@@ -15,6 +15,7 @@
#include "tinyfsm.hpp"
#include "display.hpp"
+#include "modal.hpp"
#include "screen.hpp"
#include "storage.hpp"
#include "system_events.hpp"
@@ -40,6 +41,8 @@ class UiState : public tinyfsm::Fsm<UiState> {
/* Fallback event handler. Does nothing. */
void react(const tinyfsm::Event& ev) {}
+ void react(const system_fsm::BatteryPercentChanged&);
+
virtual void react(const audio::PlaybackStarted&) {}
virtual void react(const audio::PlaybackUpdate&) {}
virtual void react(const audio::QueueUpdate&) {}
@@ -49,6 +52,12 @@ class UiState : public tinyfsm::Fsm<UiState> {
virtual void react(const internal::RecordSelected&) {}
virtual void react(const internal::IndexSelected&) {}
virtual void react(const internal::BackPressed&) {}
+ virtual void react(const internal::ModalCancelPressed&) {
+ sCurrentModal.reset();
+ }
+ virtual void react(const internal::ModalConfirmPressed&) {
+ sCurrentModal.reset();
+ }
virtual void react(const system_fsm::DisplayReady&) {}
virtual void react(const system_fsm::BootComplete&) {}
@@ -57,6 +66,7 @@ class UiState : public tinyfsm::Fsm<UiState> {
protected:
void PushScreen(std::shared_ptr<Screen>);
void PopScreen();
+ void UpdateTopBar();
static drivers::IGpios* sIGpios;
static audio::TrackQueue* sQueue;
@@ -68,6 +78,7 @@ class UiState : public tinyfsm::Fsm<UiState> {
static std::stack<std::shared_ptr<Screen>> sScreens;
static std::shared_ptr<Screen> sCurrentScreen;
+ static std::shared_ptr<Modal> sCurrentModal;
};
namespace states {
diff --git a/src/ui/lvgl_task.cpp b/src/ui/lvgl_task.cpp
index a77efa85..7d4024e5 100644
--- a/src/ui/lvgl_task.cpp
+++ b/src/ui/lvgl_task.cpp
@@ -35,6 +35,7 @@
#include "misc/lv_color.h"
#include "misc/lv_style.h"
#include "misc/lv_timer.h"
+#include "modal.hpp"
#include "relative_wheel.hpp"
#include "tasks.hpp"
#include "touchwheel.hpp"
@@ -75,6 +76,7 @@ void LvglMain(std::weak_ptr<drivers::RelativeWheel> weak_touch_wheel,
TouchWheelEncoder encoder(weak_touch_wheel);
std::shared_ptr<Screen> current_screen;
+ lv_group_t* current_group = nullptr;
auto* events = events::queues::Ui();
while (1) {
while (events->Service(0)) {
@@ -88,6 +90,11 @@ void LvglMain(std::weak_ptr<drivers::RelativeWheel> weak_touch_wheel,
current_screen = screen;
}
+ if (current_screen->group() != current_group) {
+ current_group = current_screen->group();
+ lv_indev_set_group(encoder.registration(), current_group);
+ }
+
if (current_screen) {
current_screen->Tick();
}
diff --git a/src/ui/modal.cpp b/src/ui/modal.cpp
new file mode 100644
index 00000000..c0f9b3f5
--- /dev/null
+++ b/src/ui/modal.cpp
@@ -0,0 +1,57 @@
+
+/*
+ * Copyright 2023 jacqueline <me@jacqueline.id.au>
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#include "misc/lv_color.h"
+#include "modal_progress.hpp"
+
+#include "core/lv_event.h"
+#include "esp_log.h"
+
+#include "core/lv_group.h"
+#include "core/lv_obj_pos.h"
+#include "event_queue.hpp"
+#include "extra/widgets/list/lv_list.h"
+#include "extra/widgets/menu/lv_menu.h"
+#include "extra/widgets/spinner/lv_spinner.h"
+#include "hal/lv_hal_disp.h"
+#include "index.hpp"
+#include "misc/lv_area.h"
+#include "screen.hpp"
+#include "ui_events.hpp"
+#include "ui_fsm.hpp"
+#include "widget_top_bar.hpp"
+#include "widgets/lv_label.h"
+
+namespace ui {
+
+Modal::Modal(Screen* host)
+ : root_(lv_obj_create(host->modal_content())),
+ group_(lv_group_create()),
+ host_(host) {
+ lv_obj_set_style_bg_opa(host->modal_content(), LV_OPA_40, 0);
+ lv_obj_set_style_bg_color(host->modal_content(), lv_color_black(), 0);
+
+ lv_obj_set_size(root_, 120, LV_SIZE_CONTENT);
+ lv_obj_center(root_);
+
+ lv_obj_set_style_bg_opa(root_, LV_OPA_COVER, 0);
+ lv_obj_set_style_bg_color(root_, lv_color_white(), 0);
+
+ host_->modal_group(group_);
+}
+
+Modal::~Modal() {
+ host_->modal_group(nullptr);
+ lv_obj_set_style_bg_opa(host_->modal_content(), LV_OPA_TRANSP, 0);
+
+ // The group *must* be deleted first. Otherwise, focus events will be
+ // generated whilst deleting the object tree, which causes a big mess.
+ lv_group_del(group_);
+ lv_obj_del(root_);
+}
+
+} // namespace ui
diff --git a/src/ui/modal_confirm.cpp b/src/ui/modal_confirm.cpp
new file mode 100644
index 00000000..14d56123
--- /dev/null
+++ b/src/ui/modal_confirm.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2023 jacqueline <me@jacqueline.id.au>
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#include "modal_confirm.hpp"
+
+#include "core/lv_event.h"
+#include "core/lv_obj.h"
+#include "core/lv_obj_tree.h"
+#include "esp_log.h"
+
+#include "core/lv_group.h"
+#include "core/lv_obj_pos.h"
+#include "event_queue.hpp"
+#include "extra/widgets/list/lv_list.h"
+#include "extra/widgets/menu/lv_menu.h"
+#include "extra/widgets/spinner/lv_spinner.h"
+#include "hal/lv_hal_disp.h"
+#include "index.hpp"
+#include "misc/lv_area.h"
+#include "ui_events.hpp"
+#include "ui_fsm.hpp"
+#include "widget_top_bar.hpp"
+#include "widgets/lv_btn.h"
+#include "widgets/lv_label.h"
+
+namespace ui {
+namespace modals {
+
+static void button_cancel_cb(lv_event_t* e) {
+ events::Ui().Dispatch(internal::ModalCancelPressed{});
+}
+
+static void button_confirm_cb(lv_event_t* e) {
+ events::Ui().Dispatch(internal::ModalConfirmPressed{});
+}
+
+Confirm::Confirm(Screen* host, const std::string& title_text, bool has_cancel)
+ : Modal(host) {
+ lv_obj_set_layout(root_, LV_LAYOUT_FLEX);
+ lv_obj_set_flex_flow(root_, LV_FLEX_FLOW_COLUMN);
+ lv_obj_set_flex_align(root_, LV_FLEX_ALIGN_SPACE_EVENLY, LV_FLEX_ALIGN_CENTER,
+ LV_FLEX_ALIGN_CENTER);
+
+ lv_obj_t* title = lv_label_create(root_);
+ lv_label_set_text(title, title_text.c_str());
+ lv_obj_set_size(title, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
+
+ lv_obj_t* button_container = lv_obj_create(root_);
+ lv_obj_set_size(button_container, lv_pct(100), LV_SIZE_CONTENT);
+ lv_obj_set_layout(button_container, LV_LAYOUT_FLEX);
+ lv_obj_set_flex_flow(button_container, LV_FLEX_FLOW_ROW);
+ lv_obj_set_flex_align(button_container, LV_FLEX_ALIGN_SPACE_EVENLY,
+ LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
+
+ if (has_cancel) {
+ lv_obj_t* cancel_btn = lv_btn_create(button_container);
+ lv_obj_t* cancel_label = lv_label_create(cancel_btn);
+ lv_label_set_text(cancel_label, "Cancel");
+ lv_group_add_obj(group_, cancel_btn);
+ lv_obj_add_event_cb(cancel_btn, button_cancel_cb, LV_EVENT_CLICKED, NULL);
+ }
+
+ lv_obj_t* ok_btn = lv_btn_create(button_container);
+ lv_obj_t* ok_label = lv_label_create(ok_btn);
+ lv_label_set_text(ok_label, "Okay");
+ lv_group_add_obj(group_, ok_btn);
+ lv_obj_add_event_cb(ok_btn, button_confirm_cb, LV_EVENT_CLICKED, NULL);
+}
+
+} // namespace modals
+} // namespace ui
diff --git a/src/ui/modal_progress.cpp b/src/ui/modal_progress.cpp
new file mode 100644
index 00000000..f60b324a
--- /dev/null
+++ b/src/ui/modal_progress.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2023 jacqueline <me@jacqueline.id.au>
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#include "modal_progress.hpp"
+
+#include "core/lv_event.h"
+#include "core/lv_obj.h"
+#include "core/lv_obj_tree.h"
+#include "esp_log.h"
+
+#include "core/lv_group.h"
+#include "core/lv_obj_pos.h"
+#include "event_queue.hpp"
+#include "extra/widgets/list/lv_list.h"
+#include "extra/widgets/menu/lv_menu.h"
+#include "extra/widgets/spinner/lv_spinner.h"
+#include "hal/lv_hal_disp.h"
+#include "index.hpp"
+#include "misc/lv_area.h"
+#include "ui_events.hpp"
+#include "ui_fsm.hpp"
+#include "widget_top_bar.hpp"
+#include "widgets/lv_label.h"
+
+namespace ui {
+namespace modals {
+
+Progress::Progress(Screen* host, std::string title_text) : Modal(host) {
+ lv_obj_set_layout(root_, LV_LAYOUT_FLEX);
+ lv_obj_set_flex_flow(root_, LV_FLEX_FLOW_COLUMN);
+ lv_obj_set_flex_align(root_, LV_FLEX_ALIGN_SPACE_EVENLY, LV_FLEX_ALIGN_CENTER,
+ LV_FLEX_ALIGN_CENTER);
+
+ lv_obj_t* title = lv_label_create(root_);
+ lv_label_set_text(title, title_text.c_str());
+ lv_obj_set_size(title, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
+
+ lv_obj_t* spinner = lv_spinner_create(root_, 3000, 45);
+ lv_obj_set_size(spinner, 16, 16);
+}
+
+} // namespace modals
+} // namespace ui
diff --git a/src/ui/screen.cpp b/src/ui/screen.cpp
index 7ea5e3ce..039d2439 100644
--- a/src/ui/screen.cpp
+++ b/src/ui/screen.cpp
@@ -8,10 +8,38 @@
#include <memory>
+#include "core/lv_obj_pos.h"
+#include "core/lv_obj_tree.h"
+#include "misc/lv_area.h"
+#include "misc/lv_color.h"
#include "widget_top_bar.hpp"
namespace ui {
+Screen::Screen()
+ : root_(lv_obj_create(NULL)),
+ content_(lv_obj_create(root_)),
+ modal_content_(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_center(root_);
+ lv_obj_center(content_);
+ lv_obj_center(modal_content_);
+
+ lv_obj_set_style_bg_opa(modal_content_, LV_OPA_TRANSP, 0);
+ lv_obj_set_style_bg_color(modal_content_, lv_color_black(), 0);
+}
+
+Screen::~Screen() {
+ // The group *must* be deleted first. Otherwise, focus events will be
+ // generated whilst deleting the object tree, which causes a big mess.
+ lv_group_del(group_);
+ lv_obj_del(root_);
+}
+
auto Screen::UpdateTopBar(const widgets::TopBar::State& state) -> void {
if (top_bar_) {
top_bar_->Update(state);
diff --git a/src/ui/screen_menu.cpp b/src/ui/screen_menu.cpp
index 4730db84..8c402532 100644
--- a/src/ui/screen_menu.cpp
+++ b/src/ui/screen_menu.cpp
@@ -37,18 +37,18 @@ static void item_click_cb(lv_event_t* ev) {
}
Menu::Menu(std::vector<database::IndexInfo> indexes) : indexes_(indexes) {
- lv_obj_set_layout(root_, LV_LAYOUT_FLEX);
- lv_obj_set_flex_flow(root_, LV_FLEX_FLOW_COLUMN);
- lv_obj_set_flex_align(root_, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER,
+ lv_obj_set_layout(content_, LV_LAYOUT_FLEX);
+ lv_obj_set_flex_flow(content_, LV_FLEX_FLOW_COLUMN);
+ lv_obj_set_flex_align(content_, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER,
LV_FLEX_ALIGN_CENTER);
widgets::TopBar::Configuration config{
.show_back_button = false,
.title = "",
};
- CreateTopBar(root_, config);
+ CreateTopBar(content_, config);
- lv_obj_t* list = lv_list_create(root_);
+ lv_obj_t* list = lv_list_create(content_);
lv_obj_set_size(list, lv_disp_get_hor_res(NULL), lv_disp_get_ver_res(NULL));
lv_obj_center(list);
diff --git a/src/ui/screen_playing.cpp b/src/ui/screen_playing.cpp
index cb3d866e..a1f91902 100644
--- a/src/ui/screen_playing.cpp
+++ b/src/ui/screen_playing.cpp
@@ -106,17 +106,17 @@ Playing::Playing(std::weak_ptr<database::Database> db, audio::TrackQueue* queue)
next_tracks_(),
new_track_(),
new_next_tracks_() {
- lv_obj_set_layout(root_, LV_LAYOUT_FLEX);
+ lv_obj_set_layout(content_, LV_LAYOUT_FLEX);
lv_group_set_wrap(group_, false);
- lv_obj_set_size(root_, lv_pct(100), LV_SIZE_CONTENT);
- lv_obj_set_flex_flow(root_, LV_FLEX_FLOW_COLUMN);
- lv_obj_set_flex_align(root_, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_START,
+ lv_obj_set_size(content_, lv_pct(100), LV_SIZE_CONTENT);
+ lv_obj_set_flex_flow(content_, LV_FLEX_FLOW_COLUMN);
+ lv_obj_set_flex_align(content_, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_START,
LV_FLEX_ALIGN_START);
- lv_obj_set_scrollbar_mode(root_, LV_SCROLLBAR_MODE_OFF);
+ lv_obj_set_scrollbar_mode(content_, LV_SCROLLBAR_MODE_OFF);
- lv_obj_t* above_fold_container = lv_obj_create(root_);
+ lv_obj_t* above_fold_container = lv_obj_create(content_);
lv_obj_set_layout(above_fold_container, LV_LAYOUT_FLEX);
lv_obj_set_size(above_fold_container, lv_pct(100), lv_disp_get_ver_res(NULL));
lv_obj_set_flex_flow(above_fold_container, LV_FLEX_FLOW_COLUMN);
@@ -182,7 +182,7 @@ Playing::Playing(std::weak_ptr<database::Database> db, audio::TrackQueue* queue)
lv_obj_set_style_text_font(next_up_hint_, &font_symbols, 0);
lv_obj_set_size(next_up_hint_, LV_SIZE_CONTENT, lv_pct(100));
- next_up_container_ = lv_list_create(root_);
+ next_up_container_ = lv_list_create(content_);
lv_obj_set_layout(next_up_container_, LV_LAYOUT_FLEX);
lv_obj_set_size(next_up_container_, lv_pct(100), lv_disp_get_ver_res(NULL));
lv_obj_set_flex_flow(next_up_container_, LV_FLEX_FLOW_COLUMN);
@@ -295,12 +295,12 @@ auto Playing::ApplyNextUp(const std::vector<database::Track>& tracks) -> void {
}
auto Playing::OnFocusAboveFold() -> void {
- lv_obj_scroll_to_y(root_, 0, LV_ANIM_ON);
+ lv_obj_scroll_to_y(content_, 0, LV_ANIM_ON);
}
auto Playing::OnFocusBelowFold() -> void {
- if (lv_obj_get_scroll_y(root_) < lv_obj_get_y(next_up_header_)) {
- lv_obj_scroll_to_y(root_, lv_obj_get_y(next_up_header_), LV_ANIM_ON);
+ if (lv_obj_get_scroll_y(content_) < lv_obj_get_y(next_up_header_)) {
+ lv_obj_scroll_to_y(content_, lv_obj_get_y(next_up_header_), LV_ANIM_ON);
}
}
diff --git a/src/ui/screen_track_browser.cpp b/src/ui/screen_track_browser.cpp
index 4a39578e..c534b423 100644
--- a/src/ui/screen_track_browser.cpp
+++ b/src/ui/screen_track_browser.cpp
@@ -69,14 +69,13 @@ TrackBrowser::TrackBrowser(
loading_page_(move(initial_page)),
initial_page_(),
current_pages_() {
- lv_obj_set_layout(root_, LV_LAYOUT_FLEX);
- lv_obj_set_size(root_, lv_pct(100), lv_pct(100));
- lv_obj_set_flex_flow(root_, LV_FLEX_FLOW_COLUMN);
- lv_obj_set_flex_align(root_, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER,
+ lv_obj_set_layout(content_, LV_LAYOUT_FLEX);
+ lv_obj_set_flex_flow(content_, LV_FLEX_FLOW_COLUMN);
+ lv_obj_set_flex_align(content_, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER,
LV_FLEX_ALIGN_CENTER);
// The default scrollbar is deceptive because we load in items progressively.
- lv_obj_set_scrollbar_mode(root_, LV_SCROLLBAR_MODE_OFF);
+ lv_obj_set_scrollbar_mode(content_, LV_SCROLLBAR_MODE_OFF);
// Wrapping behaves in surprising ways, again due to progressing loading.
lv_group_set_wrap(group_, false);
@@ -84,10 +83,10 @@ TrackBrowser::TrackBrowser(
.show_back_button = true,
.title = title,
};
- auto top_bar = CreateTopBar(root_, config);
+ auto top_bar = CreateTopBar(content_, config);
back_button_ = top_bar->button();
- list_ = lv_list_create(root_);
+ list_ = lv_list_create(content_);
lv_obj_set_width(list_, lv_pct(100));
lv_obj_set_flex_grow(list_, 1);
lv_obj_center(list_);
diff --git a/src/ui/ui_fsm.cpp b/src/ui/ui_fsm.cpp
index 1f83477d..8b2d3a3c 100644
--- a/src/ui/ui_fsm.cpp
+++ b/src/ui/ui_fsm.cpp
@@ -5,13 +5,18 @@
*/
#include "ui_fsm.hpp"
+
#include <memory>
-#include "audio_events.hpp"
+
#include "core/lv_obj.h"
+#include "misc/lv_gc.h"
+
+#include "audio_events.hpp"
#include "display.hpp"
#include "event_queue.hpp"
#include "gpios.hpp"
#include "lvgl_task.hpp"
+#include "modal_confirm.hpp"
#include "relative_wheel.hpp"
#include "screen.hpp"
#include "screen_menu.hpp"
@@ -23,6 +28,7 @@
#include "touchwheel.hpp"
#include "track_queue.hpp"
#include "ui_events.hpp"
+#include "widget_top_bar.hpp"
namespace ui {
@@ -40,6 +46,7 @@ std::weak_ptr<database::Database> UiState::sDb;
std::stack<std::shared_ptr<Screen>> UiState::sScreens;
std::shared_ptr<Screen> UiState::sCurrentScreen;
+std::shared_ptr<Modal> UiState::sCurrentModal;
auto UiState::Init(drivers::IGpios* gpio_expander, audio::TrackQueue* queue)
-> bool {
@@ -75,6 +82,7 @@ void UiState::PushScreen(std::shared_ptr<Screen> screen) {
sScreens.push(sCurrentScreen);
}
sCurrentScreen = screen;
+ UpdateTopBar();
}
void UiState::PopScreen() {
@@ -83,12 +91,28 @@ void UiState::PopScreen() {
}
sCurrentScreen = sScreens.top();
sScreens.pop();
+ UpdateTopBar();
}
void UiState::react(const system_fsm::KeyLockChanged& ev) {
sDisplay->SetDisplayOn(ev.falling);
}
+void UiState::react(const system_fsm::BatteryPercentChanged&) {
+ UpdateTopBar();
+}
+
+void UiState::UpdateTopBar() {
+ widgets::TopBar::State state{
+ .playback_state = widgets::TopBar::PlaybackState::kIdle,
+ .battery_percent = 50,
+ .is_charging = true,
+ };
+ if (sCurrentScreen) {
+ sCurrentScreen->UpdateTopBar(state);
+ }
+}
+
namespace states {
void Splash::exit() {