summaryrefslogtreecommitdiff
path: root/src/ui
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2023-09-28 10:43:48 +1000
committerjacqueline <me@jacqueline.id.au>2023-09-28 10:43:48 +1000
commit6a47edcd35884095946f761fa3aa2367c7c26442 (patch)
tree5b34e1bf14759dcc78b6611b1b6538dc03119860 /src/ui
parentf09ba5ffd53bf7d28e0dc516c00a8f69ca7efae9 (diff)
downloadtangara-fw-6a47edcd35884095946f761fa3aa2367c7c26442.tar.gz
Use databinding for the top bar. It's so nice now!
Diffstat (limited to 'src/ui')
-rw-r--r--src/ui/include/model_top_bar.hpp26
-rw-r--r--src/ui/include/screen.hpp12
-rw-r--r--src/ui/include/screen_menu.hpp3
-rw-r--r--src/ui/include/screen_playing.hpp4
-rw-r--r--src/ui/include/screen_settings.hpp19
-rw-r--r--src/ui/include/screen_track_browser.hpp2
-rw-r--r--src/ui/include/ui_fsm.hpp5
-rw-r--r--src/ui/include/widget_top_bar.hpp27
-rw-r--r--src/ui/screen.cpp19
-rw-r--r--src/ui/screen_menu.cpp5
-rw-r--r--src/ui/screen_playing.cpp6
-rw-r--r--src/ui/screen_settings.cpp29
-rw-r--r--src/ui/screen_track_browser.cpp4
-rw-r--r--src/ui/ui_fsm.cpp74
-rw-r--r--src/ui/widget_top_bar.cpp81
15 files changed, 164 insertions, 152 deletions
diff --git a/src/ui/include/model_top_bar.hpp b/src/ui/include/model_top_bar.hpp
new file mode 100644
index 00000000..c0f148f3
--- /dev/null
+++ b/src/ui/include/model_top_bar.hpp
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2023 jacqueline <me@jacqueline.id.au>
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#pragma once
+
+#include "battery.hpp"
+#include "bindey/property.h"
+
+#include "track.hpp"
+
+namespace ui {
+namespace models {
+
+struct TopBar {
+ bindey::property<battery::Battery::BatteryState> battery_state;
+
+ // Shared with the Playback model
+ bindey::property<bool>& is_playing;
+ bindey::property<std::optional<database::TrackId>>& current_track;
+};
+
+} // namespace models
+} // namespace ui
diff --git a/src/ui/include/screen.hpp b/src/ui/include/screen.hpp
index ac7b19f8..e9eaeeb0 100644
--- a/src/ui/include/screen.hpp
+++ b/src/ui/include/screen.hpp
@@ -16,6 +16,7 @@
#include "core/lv_obj_tree.h"
#include "event_binding.hpp"
#include "lvgl.h"
+#include "model_top_bar.hpp"
#include "nod/nod.hpp"
#include "widget_top_bar.hpp"
@@ -37,8 +38,6 @@ class Screen {
*/
virtual auto Tick() -> void {}
- auto UpdateTopBar(const widgets::TopBar::State& state) -> void;
-
auto root() -> lv_obj_t* { return root_; }
auto content() -> lv_obj_t* { return content_; }
@@ -52,8 +51,9 @@ class Screen {
}
protected:
- auto CreateTopBar(lv_obj_t* parent, const widgets::TopBar::Configuration&)
- -> widgets::TopBar*;
+ auto CreateTopBar(lv_obj_t* parent,
+ const widgets::TopBar::Configuration&,
+ models::TopBar& model) -> widgets::TopBar*;
std::pmr::vector<bindey::scoped_binding> data_bindings_;
std::pmr::vector<std::unique_ptr<EventBinding>> event_bindings_;
@@ -78,7 +78,9 @@ class Screen {
class MenuScreen : public Screen {
public:
- MenuScreen(const std::pmr::string& title, bool show_back_button = true);
+ MenuScreen(models::TopBar&,
+ const std::pmr::string& title,
+ bool show_back_button = true);
};
} // namespace ui
diff --git a/src/ui/include/screen_menu.hpp b/src/ui/include/screen_menu.hpp
index be2a9493..a83346f6 100644
--- a/src/ui/include/screen_menu.hpp
+++ b/src/ui/include/screen_menu.hpp
@@ -12,6 +12,7 @@
#include "index.hpp"
#include "lvgl.h"
+#include "model_top_bar.hpp"
#include "screen.hpp"
#include "screen_settings.hpp"
@@ -20,7 +21,7 @@ namespace screens {
class Menu : public MenuScreen {
public:
- explicit Menu(std::vector<database::IndexInfo> indexes);
+ explicit Menu(models::TopBar&, std::vector<database::IndexInfo> indexes);
~Menu();
private:
diff --git a/src/ui/include/screen_playing.hpp b/src/ui/include/screen_playing.hpp
index fff9cc35..185c55cc 100644
--- a/src/ui/include/screen_playing.hpp
+++ b/src/ui/include/screen_playing.hpp
@@ -18,6 +18,7 @@
#include "database.hpp"
#include "future_fetcher.hpp"
#include "model_playback.hpp"
+#include "model_top_bar.hpp"
#include "screen.hpp"
#include "track.hpp"
#include "track_queue.hpp"
@@ -31,7 +32,8 @@ namespace screens {
*/
class Playing : public Screen {
public:
- explicit Playing(models::Playback& playback_model,
+ explicit Playing(models::TopBar&,
+ models::Playback& playback_model,
std::weak_ptr<database::Database> db,
audio::TrackQueue& queue);
~Playing();
diff --git a/src/ui/include/screen_settings.hpp b/src/ui/include/screen_settings.hpp
index 4e1936a2..1a4672ed 100644
--- a/src/ui/include/screen_settings.hpp
+++ b/src/ui/include/screen_settings.hpp
@@ -18,6 +18,7 @@
#include "index.hpp"
#include "lvgl.h"
+#include "model_top_bar.hpp"
#include "nvs.hpp"
#include "screen.hpp"
@@ -26,12 +27,12 @@ namespace screens {
class Settings : public MenuScreen {
public:
- Settings();
+ Settings(models::TopBar&);
};
class Bluetooth : public MenuScreen {
public:
- Bluetooth(drivers::Bluetooth& bt, drivers::NvsStorage& nvs);
+ Bluetooth(models::TopBar&, drivers::Bluetooth& bt, drivers::NvsStorage& nvs);
auto ChangeEnabledState(bool enabled) -> void;
auto RefreshDevicesList() -> void;
@@ -53,7 +54,7 @@ class Bluetooth : public MenuScreen {
class Headphones : public MenuScreen {
public:
- Headphones(drivers::NvsStorage& nvs);
+ Headphones(models::TopBar&, drivers::NvsStorage& nvs);
auto ChangeMaxVolume(uint8_t index) -> void;
auto ChangeCustomVolume(int8_t diff) -> void;
@@ -71,7 +72,9 @@ class Headphones : public MenuScreen {
class Appearance : public MenuScreen {
public:
- Appearance(drivers::NvsStorage& nvs, drivers::Display& display);
+ Appearance(models::TopBar&,
+ drivers::NvsStorage& nvs,
+ drivers::Display& display);
auto ChangeBrightness(uint_fast8_t) -> void;
auto CommitBrightness() -> void;
@@ -86,22 +89,22 @@ class Appearance : public MenuScreen {
class InputMethod : public MenuScreen {
public:
- InputMethod();
+ InputMethod(models::TopBar&);
};
class Storage : public MenuScreen {
public:
- Storage();
+ Storage(models::TopBar&);
};
class FirmwareUpdate : public MenuScreen {
public:
- FirmwareUpdate();
+ FirmwareUpdate(models::TopBar&);
};
class About : public MenuScreen {
public:
- About();
+ About(models::TopBar&);
};
} // namespace screens
diff --git a/src/ui/include/screen_track_browser.hpp b/src/ui/include/screen_track_browser.hpp
index fdeb3afe..719306f0 100644
--- a/src/ui/include/screen_track_browser.hpp
+++ b/src/ui/include/screen_track_browser.hpp
@@ -14,6 +14,7 @@
#include "lvgl.h"
#include "database.hpp"
+#include "model_top_bar.hpp"
#include "screen.hpp"
namespace ui {
@@ -22,6 +23,7 @@ namespace screens {
class TrackBrowser : public Screen {
public:
TrackBrowser(
+ models::TopBar&,
std::weak_ptr<database::Database> db,
const std::pmr::string& title,
std::future<database::Result<database::IndexRecord>*>&& initial_page);
diff --git a/src/ui/include/ui_fsm.hpp b/src/ui/include/ui_fsm.hpp
index cb3e651c..24f0c270 100644
--- a/src/ui/include/ui_fsm.hpp
+++ b/src/ui/include/ui_fsm.hpp
@@ -17,6 +17,7 @@
#include "gpios.hpp"
#include "lvgl_task.hpp"
#include "model_playback.hpp"
+#include "model_top_bar.hpp"
#include "nvs.hpp"
#include "relative_wheel.hpp"
#include "screen_playing.hpp"
@@ -82,7 +83,6 @@ class UiState : public tinyfsm::Fsm<UiState> {
protected:
void PushScreen(std::shared_ptr<Screen>);
void PopScreen();
- void UpdateTopBar();
static std::unique_ptr<UiTask> sTask;
static std::shared_ptr<system_fsm::ServiceLocator> sServices;
@@ -94,8 +94,7 @@ class UiState : public tinyfsm::Fsm<UiState> {
static std::shared_ptr<Modal> sCurrentModal;
static models::Playback sPlaybackModel;
-
- static bindey::property<battery::Battery::BatteryState> sPropBatteryState;
+ static models::TopBar sTopBarModel;
};
namespace states {
diff --git a/src/ui/include/widget_top_bar.hpp b/src/ui/include/widget_top_bar.hpp
index 1a2c826a..b240188c 100644
--- a/src/ui/include/widget_top_bar.hpp
+++ b/src/ui/include/widget_top_bar.hpp
@@ -9,9 +9,11 @@
#include <cstdint>
#include <string>
+#include "bindey/binding.h"
#include "lvgl.h"
#include "memory_resource.hpp"
+#include "model_top_bar.hpp"
namespace ui {
@@ -24,33 +26,18 @@ class TopBar {
std::pmr::string title;
};
- enum class PlaybackState {
- kIdle,
- kPaused,
- kPlaying,
- };
-
- struct State {
- PlaybackState playback_state;
- uint_fast8_t battery_percent;
- bool is_charging;
- };
-
- explicit TopBar(lv_obj_t* parent, const Configuration& config);
+ explicit TopBar(lv_obj_t* parent,
+ const Configuration& config,
+ models::TopBar& model);
auto root() -> lv_obj_t* { return container_; }
auto button() -> lv_obj_t* { return back_button_; }
- auto Update(const State&) -> void;
-
private:
- lv_obj_t* container_;
+ std::vector<bindey::scoped_binding> bindings_;
+ lv_obj_t* container_;
lv_obj_t* back_button_;
- lv_obj_t* title_;
- lv_obj_t* playback_;
- lv_obj_t* battery_;
- lv_obj_t* charging_;
};
} // namespace widgets
diff --git a/src/ui/screen.cpp b/src/ui/screen.cpp
index 48bffff7..bdc30fcd 100644
--- a/src/ui/screen.cpp
+++ b/src/ui/screen.cpp
@@ -12,6 +12,7 @@
#include "core/lv_obj_tree.h"
#include "misc/lv_area.h"
#include "misc/lv_color.h"
+#include "model_top_bar.hpp"
#include "widget_top_bar.hpp"
namespace ui {
@@ -40,24 +41,20 @@ Screen::~Screen() {
lv_obj_del(root_);
}
-auto Screen::UpdateTopBar(const widgets::TopBar::State& state) -> void {
- if (top_bar_) {
- top_bar_->Update(state);
- }
-}
-
auto Screen::CreateTopBar(lv_obj_t* parent,
- const widgets::TopBar::Configuration& config)
- -> widgets::TopBar* {
+ const widgets::TopBar::Configuration& config,
+ models::TopBar& model) -> widgets::TopBar* {
assert(top_bar_ == nullptr);
- top_bar_ = std::make_unique<widgets::TopBar>(parent, config);
+ top_bar_ = std::make_unique<widgets::TopBar>(parent, config, model);
if (top_bar_->button()) {
lv_group_add_obj(group_, top_bar_->button());
}
return top_bar_.get();
}
-MenuScreen::MenuScreen(const std::pmr::string& title, bool show_back_button)
+MenuScreen::MenuScreen(models::TopBar& top_bar_model,
+ const std::pmr::string& title,
+ bool show_back_button)
: Screen() {
lv_group_set_wrap(group_, false);
@@ -70,7 +67,7 @@ MenuScreen::MenuScreen(const std::pmr::string& title, bool show_back_button)
.show_back_button = show_back_button,
.title = title.c_str(),
};
- CreateTopBar(content_, config);
+ CreateTopBar(content_, config, top_bar_model);
content_ = lv_obj_create(content_);
lv_obj_set_flex_grow(content_, 1);
diff --git a/src/ui/screen_menu.cpp b/src/ui/screen_menu.cpp
index 3d36c017..44f49b32 100644
--- a/src/ui/screen_menu.cpp
+++ b/src/ui/screen_menu.cpp
@@ -18,6 +18,7 @@
#include "hal/lv_hal_disp.h"
#include "index.hpp"
#include "misc/lv_area.h"
+#include "model_top_bar.hpp"
#include "ui_events.hpp"
#include "ui_fsm.hpp"
#include "widget_top_bar.hpp"
@@ -45,8 +46,8 @@ static void index_click_cb(lv_event_t* ev) {
events::Ui().Dispatch(internal::IndexSelected{.index = *index});
}
-Menu::Menu(std::vector<database::IndexInfo> indexes)
- : MenuScreen(" ", false), indexes_(indexes) {
+Menu::Menu(models::TopBar& top_bar, std::vector<database::IndexInfo> indexes)
+ : MenuScreen(top_bar, " ", false), indexes_(indexes) {
lv_obj_t* list = lv_list_create(content_);
lv_obj_set_size(list, lv_pct(100), lv_pct(100));
diff --git a/src/ui/screen_playing.cpp b/src/ui/screen_playing.cpp
index 547bcf98..54e5feaf 100644
--- a/src/ui/screen_playing.cpp
+++ b/src/ui/screen_playing.cpp
@@ -37,6 +37,7 @@
#include "misc/lv_color.h"
#include "misc/lv_txt.h"
#include "model_playback.hpp"
+#include "model_top_bar.hpp"
#include "track.hpp"
#include "ui_events.hpp"
#include "ui_fsm.hpp"
@@ -101,7 +102,8 @@ auto Playing::next_up_label(lv_obj_t* parent, const std::pmr::string& text)
return button;
}
-Playing::Playing(models::Playback& playback_model,
+Playing::Playing(models::TopBar& top_bar_model,
+ models::Playback& playback_model,
std::weak_ptr<database::Database> db,
audio::TrackQueue& queue)
: db_(db),
@@ -158,7 +160,7 @@ Playing::Playing(models::Playback& playback_model,
.show_back_button = true,
.title = "Now Playing",
};
- CreateTopBar(above_fold_container, config);
+ CreateTopBar(above_fold_container, config, top_bar_model);
lv_obj_t* info_container = lv_obj_create(above_fold_container);
lv_obj_set_layout(info_container, LV_LAYOUT_FLEX);
diff --git a/src/ui/screen_settings.cpp b/src/ui/screen_settings.cpp
index a480f920..a2dc4296 100644
--- a/src/ui/screen_settings.cpp
+++ b/src/ui/screen_settings.cpp
@@ -29,6 +29,7 @@
#include "index.hpp"
#include "misc/lv_anim.h"
#include "misc/lv_area.h"
+#include "model_top_bar.hpp"
#include "nvs.hpp"
#include "screen.hpp"
#include "ui_events.hpp"
@@ -64,7 +65,7 @@ static void sub_menu(lv_obj_t* list,
reinterpret_cast<void*>(static_cast<uintptr_t>(page)));
}
-Settings::Settings() : MenuScreen("Settings") {
+Settings::Settings(models::TopBar& bar) : MenuScreen(bar, "Settings") {
lv_obj_t* list = lv_list_create(content_);
lv_obj_set_size(list, lv_pct(100), lv_pct(100));
@@ -113,8 +114,10 @@ static auto select_device_cb(lv_event_t* ev) {
instance->OnDeviceSelected(lv_obj_get_index(ev->target));
}
-Bluetooth::Bluetooth(drivers::Bluetooth& bt, drivers::NvsStorage& nvs)
- : MenuScreen("Bluetooth"), bt_(bt), nvs_(nvs) {
+Bluetooth::Bluetooth(models::TopBar& bar,
+ drivers::Bluetooth& bt,
+ drivers::NvsStorage& nvs)
+ : MenuScreen(bar, "Bluetooth"), bt_(bt), nvs_(nvs) {
lv_obj_t* toggle_container = settings_container(content_);
lv_obj_t* toggle_label = lv_label_create(toggle_container);
lv_label_set_text(toggle_label, "Enable");
@@ -268,8 +271,8 @@ static void decrease_vol_limit_cb(lv_event_t* ev) {
instance->ChangeCustomVolume(-2);
}
-Headphones::Headphones(drivers::NvsStorage& nvs)
- : MenuScreen("Headphones"), nvs_(nvs), custom_limit_(0) {
+Headphones::Headphones(models::TopBar& bar, drivers::NvsStorage& nvs)
+ : MenuScreen(bar, "Headphones"), nvs_(nvs), custom_limit_(0) {
uint16_t reference = drivers::wm8523::kLineLevelReferenceVolume;
index_to_level_.push_back(reference - (10 * 4));
index_to_level_.push_back(reference + (6 * 4));
@@ -377,8 +380,10 @@ static auto brightness_str(uint_fast8_t percent) -> std::string {
return std::to_string(percent) + "%";
}
-Appearance::Appearance(drivers::NvsStorage& nvs, drivers::Display& display)
- : MenuScreen("Appearance"), nvs_(nvs), display_(display) {
+Appearance::Appearance(models::TopBar& bar,
+ drivers::NvsStorage& nvs,
+ drivers::Display& display)
+ : MenuScreen(bar, "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);
@@ -417,7 +422,8 @@ auto Appearance::CommitBrightness() -> void {
nvs_.ScreenBrightness(current_brightness_);
}
-InputMethod::InputMethod() : MenuScreen("Input Method") {
+InputMethod::InputMethod(models::TopBar& bar)
+ : MenuScreen(bar, "Input Method") {
lv_obj_t* wheel_label = lv_label_create(content_);
lv_label_set_text(wheel_label, "What does the wheel do?");
lv_obj_t* wheel_dropdown = lv_dropdown_create(content_);
@@ -431,7 +437,7 @@ InputMethod::InputMethod() : MenuScreen("Input Method") {
lv_group_add_obj(group_, buttons_dropdown);
}
-Storage::Storage() : MenuScreen("Storage") {
+Storage::Storage(models::TopBar& bar) : MenuScreen(bar, "Storage") {
label_pair(content_, "Storage Capacity:", "32 GiB");
label_pair(content_, "Currently Used:", "6 GiB");
label_pair(content_, "DB Size:", "1.2 MiB");
@@ -446,7 +452,8 @@ Storage::Storage() : MenuScreen("Storage") {
lv_group_add_obj(group_, reset_btn);
}
-FirmwareUpdate::FirmwareUpdate() : MenuScreen("Firmware Update") {
+FirmwareUpdate::FirmwareUpdate(models::TopBar& bar)
+ : MenuScreen(bar, "Firmware Update") {
label_pair(content_, "ESP32 FW:", "vIDKLOL");
label_pair(content_, "SAMD21 FW:", "vIDKLOL");
@@ -461,7 +468,7 @@ FirmwareUpdate::FirmwareUpdate() : MenuScreen("Firmware Update") {
lv_group_add_obj(group_, flash_samd_btn);
}
-About::About() : MenuScreen("About") {
+About::About(models::TopBar& bar) : MenuScreen(bar, "About") {
lv_obj_t* label = lv_label_create(content_);
lv_label_set_text(label, "Some licenses or whatever");
}
diff --git a/src/ui/screen_track_browser.cpp b/src/ui/screen_track_browser.cpp
index 8d1fe653..ba27ad5e 100644
--- a/src/ui/screen_track_browser.cpp
+++ b/src/ui/screen_track_browser.cpp
@@ -16,6 +16,7 @@
#include "font/lv_symbol_def.h"
#include "lvgl.h"
#include "misc/lv_anim.h"
+#include "model_top_bar.hpp"
#include "screen_menu.hpp"
#include "core/lv_event.h"
@@ -59,6 +60,7 @@ static void item_select_cb(lv_event_t* ev) {
}
TrackBrowser::TrackBrowser(
+ models::TopBar& top_bar_model,
std::weak_ptr<database::Database> db,
const std::pmr::string& title,
std::future<database::Result<database::IndexRecord>*>&& initial_page)
@@ -83,7 +85,7 @@ TrackBrowser::TrackBrowser(
.show_back_button = true,
.title = title,
};
- auto top_bar = CreateTopBar(content_, config);
+ auto top_bar = CreateTopBar(content_, config, top_bar_model);
back_button_ = top_bar->button();
list_ = lv_list_create(content_);
diff --git a/src/ui/ui_fsm.cpp b/src/ui/ui_fsm.cpp
index d7bb9bb7..f66e3e8a 100644
--- a/src/ui/ui_fsm.cpp
+++ b/src/ui/ui_fsm.cpp
@@ -54,8 +54,9 @@ std::shared_ptr<Screen> UiState::sCurrentScreen;
std::shared_ptr<Modal> UiState::sCurrentModal;
models::Playback UiState::sPlaybackModel;
-
-bindey::property<battery::Battery::BatteryState> UiState::sPropBatteryState;
+models::TopBar UiState::sTopBarModel{{},
+ UiState::sPlaybackModel.is_playing,
+ UiState::sPlaybackModel.current_track};
auto UiState::InitBootSplash(drivers::IGpios& gpios) -> bool {
// Init LVGL first, since the display driver registers itself with LVGL.
@@ -75,7 +76,6 @@ void UiState::PushScreen(std::shared_ptr<Screen> screen) {
sScreens.push(sCurrentScreen);
}
sCurrentScreen = screen;
- UpdateTopBar();
}
void UiState::PopScreen() {
@@ -84,7 +84,6 @@ void UiState::PopScreen() {
}
sCurrentScreen = sScreens.top();
sScreens.pop();
- UpdateTopBar();
}
void UiState::react(const system_fsm::KeyLockChanged& ev) {
@@ -93,14 +92,8 @@ void UiState::react(const system_fsm::KeyLockChanged& ev) {
: std::shared_ptr<TouchWheelEncoder>());
}
-void UiState::react(const system_fsm::BatteryStateChanged&) {
- if (!sServices) {
- return;
- }
- auto state = sServices->battery().State();
- if (state) {
- sPropBatteryState.set(*state);
- }
+void UiState::react(const system_fsm::BatteryStateChanged& ev) {
+ sTopBarModel.battery_state.set(ev.new_state);
}
void UiState::react(const audio::PlaybackStarted&) {
@@ -117,34 +110,11 @@ void UiState::react(const audio::PlaybackUpdate& ev) {
}
void UiState::react(const audio::QueueUpdate&) {
- ESP_LOGI(kTag, "current changed!");
auto& queue = sServices->track_queue();
sPlaybackModel.current_track.set(queue.GetCurrent());
sPlaybackModel.upcoming_tracks.set(queue.GetUpcoming(10));
}
-void UiState::UpdateTopBar() {
- auto battery_state = sServices->battery().State();
- bool has_queue = sServices->track_queue().GetCurrent().has_value();
- bool is_playing = audio::AudioState::is_in_state<audio::states::Playback>();
-
- widgets::TopBar::State state{
- .playback_state = widgets::TopBar::PlaybackState::kIdle,
- .battery_percent = static_cast<uint_fast8_t>(
- battery_state.has_value() ? battery_state->percent : 100),
- .is_charging = !battery_state.has_value() || battery_state->is_charging,
- };
-
- if (has_queue) {
- state.playback_state = is_playing ? widgets::TopBar::PlaybackState::kPlaying
- : widgets::TopBar::PlaybackState::kPaused;
- }
-
- if (sCurrentScreen) {
- sCurrentScreen->UpdateTopBar(state);
- }
-}
-
namespace states {
void Splash::exit() {
@@ -242,7 +212,8 @@ void Browse::entry() {
if (!db) {
return;
}
- sCurrentScreen = std::make_shared<screens::Menu>(db->GetIndexes());
+ sCurrentScreen =
+ std::make_shared<screens::Menu>(sTopBarModel, db->GetIndexes());
sBrowseFirstEntry = false;
}
}
@@ -253,7 +224,8 @@ void Browse::react(const system_fsm::StorageMounted& ev) {
if (!db) {
return;
}
- sCurrentScreen = std::make_shared<screens::Menu>(db->GetIndexes());
+ sCurrentScreen =
+ std::make_shared<screens::Menu>(sTopBarModel, db->GetIndexes());
sBrowseFirstEntry = false;
}
}
@@ -267,31 +239,32 @@ void Browse::react(const internal::ShowSettingsPage& ev) {
std::shared_ptr<screens::Bluetooth> bt_screen;
switch (ev.page) {
case internal::ShowSettingsPage::Page::kRoot:
- screen.reset(new screens::Settings());
+ screen.reset(new screens::Settings(sTopBarModel));
break;
case internal::ShowSettingsPage::Page::kBluetooth:
- bt_screen = std::make_shared<screens::Bluetooth>(sServices->bluetooth(),
- sServices->nvs());
+ bt_screen = std::make_shared<screens::Bluetooth>(
+ sTopBarModel, sServices->bluetooth(), sServices->nvs());
screen = bt_screen;
bluetooth_screen_ = bt_screen;
break;
case internal::ShowSettingsPage::Page::kHeadphones:
- screen.reset(new screens::Headphones(sServices->nvs()));
+ screen.reset(new screens::Headphones(sTopBarModel, sServices->nvs()));
break;
case internal::ShowSettingsPage::Page::kAppearance:
- screen.reset(new screens::Appearance(sServices->nvs(), *sDisplay));
+ screen.reset(
+ new screens::Appearance(sTopBarModel, sServices->nvs(), *sDisplay));
break;
case internal::ShowSettingsPage::Page::kInput:
- screen.reset(new screens::InputMethod());
+ screen.reset(new screens::InputMethod(sTopBarModel));
break;
case internal::ShowSettingsPage::Page::kStorage:
- screen.reset(new screens::Storage());
+ screen.reset(new screens::Storage(sTopBarModel));
break;
case internal::ShowSettingsPage::Page::kFirmwareUpdate:
- screen.reset(new screens::FirmwareUpdate());
+ screen.reset(new screens::FirmwareUpdate(sTopBarModel));
break;
case internal::ShowSettingsPage::Page::kAbout:
- screen.reset(new screens::About());
+ screen.reset(new screens::About(sTopBarModel));
break;
}
if (screen) {
@@ -323,7 +296,7 @@ void Browse::react(const internal::RecordSelected& ev) {
auto query = db->GetPage(&cont.value());
std::pmr::string title = record->text().value_or("TODO");
PushScreen(std::make_shared<screens::TrackBrowser>(
- sServices->database(), title, std::move(query)));
+ sTopBarModel, sServices->database(), title, std::move(query)));
}
}
@@ -336,7 +309,7 @@ void Browse::react(const internal::IndexSelected& ev) {
ESP_LOGI(kTag, "selected index %s", ev.index.name.c_str());
auto query = db->GetTracksByIndex(ev.index, kRecordsPerPage);
PushScreen(std::make_shared<screens::TrackBrowser>(
- sServices->database(), ev.index.name, std::move(query)));
+ sTopBarModel, sServices->database(), ev.index.name, std::move(query)));
}
void Browse::react(const internal::BackPressed& ev) {
@@ -354,8 +327,9 @@ static std::shared_ptr<screens::Playing> sPlayingScreen;
void Playing::entry() {
ESP_LOGI(kTag, "push playing screen");
- sPlayingScreen.reset(new screens::Playing(
- sPlaybackModel, sServices->database(), sServices->track_queue()));
+ sPlayingScreen.reset(new screens::Playing(sTopBarModel, sPlaybackModel,
+ sServices->database(),
+ sServices->track_queue()));
PushScreen(sPlayingScreen);
}
diff --git a/src/ui/widget_top_bar.cpp b/src/ui/widget_top_bar.cpp
index c38f4fe2..ba9ee5cb 100644
--- a/src/ui/widget_top_bar.cpp
+++ b/src/ui/widget_top_bar.cpp
@@ -5,13 +5,16 @@
*/
#include "widget_top_bar.hpp"
+#include "battery.hpp"
#include "core/lv_group.h"
#include "core/lv_obj.h"
#include "event_queue.hpp"
#include "extra/layouts/flex/lv_flex.h"
#include "font/lv_symbol_def.h"
#include "font_symbols.hpp"
+#include "model_top_bar.hpp"
#include "themes.hpp"
+#include "track.hpp"
#include "ui_events.hpp"
#include "ui_fsm.hpp"
#include "widgets/lv_img.h"
@@ -34,7 +37,9 @@ static void back_click_cb(lv_event_t* ev) {
events::Ui().Dispatch(internal::BackPressed{});
}
-TopBar::TopBar(lv_obj_t* parent, const Configuration& config) {
+TopBar::TopBar(lv_obj_t* parent,
+ const Configuration& config,
+ models::TopBar& model) {
container_ = lv_obj_create(parent);
lv_obj_set_size(container_, lv_pct(100), 20);
lv_obj_set_flex_flow(container_, LV_FLEX_FLOW_ROW);
@@ -54,49 +59,51 @@ TopBar::TopBar(lv_obj_t* parent, const Configuration& config) {
back_button_ = nullptr;
}
- title_ = lv_label_create(container_);
+ lv_obj_t* title_ = lv_label_create(container_);
lv_label_set_text(title_, config.title.c_str());
lv_obj_set_flex_grow(title_, 1);
- playback_ = lv_img_create(container_);
- battery_ = lv_img_create(container_);
- charging_ = lv_label_create(container_);
+ lv_obj_t* playback = lv_img_create(container_);
- themes::Theme::instance()->ApplyStyle(container_, themes::Style::kTopBar);
-}
+ bindings_.push_back(model.is_playing.onChangedAndNow([=](bool is_playing) {
+ lv_img_set_src(playback, is_playing ? &kIconPlay : &kIconPause);
+ }));
+ bindings_.push_back(model.current_track.onChangedAndNow(
+ [=](const std::optional<database::TrackId>& id) {
+ if (id) {
+ lv_obj_clear_flag(playback, LV_OBJ_FLAG_HIDDEN);
+ } else {
+ lv_obj_add_flag(playback, LV_OBJ_FLAG_HIDDEN);
+ }
+ }));
-auto TopBar::Update(const State& state) -> void {
- switch (state.playback_state) {
- case PlaybackState::kIdle:
- lv_img_set_src(playback_, NULL);
- break;
- case PlaybackState::kPaused:
- lv_img_set_src(playback_, &kIconPause);
- break;
- case PlaybackState::kPlaying:
- lv_img_set_src(playback_, &kIconPlay);
- break;
- }
+ lv_obj_t* battery = lv_img_create(container_);
+ lv_obj_t* charging = lv_label_create(container_);
- if (state.is_charging) {
- lv_label_set_text(charging_, "+");
- } else {
- lv_label_set_text(charging_, "");
- }
+ bindings_.push_back(model.battery_state.onChangedAndNow(
+ [=](const battery::Battery::BatteryState& state) {
+ if (state.is_charging) {
+ lv_label_set_text(charging, "+");
+ } else {
+ lv_label_set_text(charging, "");
+ }
- if (state.battery_percent >= 95) {
- lv_img_set_src(battery_, &kIconBatteryFull);
- } else if (state.battery_percent >= 75) {
- lv_img_set_src(battery_, &kIconBattery80);
- } else if (state.battery_percent >= 55) {
- lv_img_set_src(battery_, &kIconBattery60);
- } else if (state.battery_percent >= 35) {
- lv_img_set_src(battery_, &kIconBattery40);
- } else if (state.battery_percent >= 15) {
- lv_img_set_src(battery_, &kIconBattery20);
- } else {
- lv_img_set_src(battery_, &kIconBatteryEmpty);
- }
+ if (state.percent >= 95) {
+ lv_img_set_src(battery, &kIconBatteryFull);
+ } else if (state.percent >= 75) {
+ lv_img_set_src(battery, &kIconBattery80);
+ } else if (state.percent >= 55) {
+ lv_img_set_src(battery, &kIconBattery60);
+ } else if (state.percent >= 35) {
+ lv_img_set_src(battery, &kIconBattery40);
+ } else if (state.percent >= 15) {
+ lv_img_set_src(battery, &kIconBattery20);
+ } else {
+ lv_img_set_src(battery, &kIconBatteryEmpty);
+ }
+ }));
+
+ themes::Theme::instance()->ApplyStyle(container_, themes::Style::kTopBar);
}
} // namespace widgets