Use databinding for the top bar. It's so nice now!

custom
jacqueline 2 years ago
parent f09ba5ffd5
commit 6a47edcd35
  1. 4
      src/app_console/app_console.cpp
  2. 18
      src/battery/battery.cpp
  3. 5
      src/system_fsm/include/system_events.hpp
  4. 26
      src/ui/include/model_top_bar.hpp
  5. 12
      src/ui/include/screen.hpp
  6. 3
      src/ui/include/screen_menu.hpp
  7. 4
      src/ui/include/screen_playing.hpp
  8. 19
      src/ui/include/screen_settings.hpp
  9. 2
      src/ui/include/screen_track_browser.hpp
  10. 5
      src/ui/include/ui_fsm.hpp
  11. 27
      src/ui/include/widget_top_bar.hpp
  12. 19
      src/ui/screen.cpp
  13. 5
      src/ui/screen_menu.cpp
  14. 6
      src/ui/screen_playing.cpp
  15. 29
      src/ui/screen_settings.cpp
  16. 4
      src/ui/screen_track_browser.cpp
  17. 74
      src/ui/ui_fsm.cpp
  18. 81
      src/ui/widget_top_bar.cpp

@ -336,7 +336,6 @@ void RegisterDbDump() {
esp_console_cmd_register(&cmd);
}
#if CONFIG_APPTRACE_ENABLE
int CmdTasks(int argc, char** argv) {
if (!configUSE_TRACE_FACILITY) {
std::cout << "configUSE_TRACE_FACILITY must be enabled" << std::endl;
@ -446,7 +445,6 @@ void RegisterTasks() {
.argtable = NULL};
esp_console_cmd_register(&cmd);
}
#endif
int CmdHeaps(int argc, char** argv) {
static const std::pmr::string usage = "usage: heaps";
@ -638,9 +636,7 @@ auto AppConsole::RegisterExtraComponents() -> void {
RegisterDbTracks();
RegisterDbIndex();
RegisterDbDump();
#if CONFIG_APPTRACE_ENABLE
RegisterTasks();
#endif
RegisterHeaps();

@ -77,15 +77,16 @@ auto Battery::Update() -> void {
*charge_state == ChargeStatus::kChargingFast ||
*charge_state == ChargeStatus::kFullCharge;
if (!state_ || state_->is_charging != is_charging ||
state_->percent != percent) {
EmitEvent();
if (state_ && state_->is_charging == is_charging &&
state_->percent == percent) {
return;
}
state_ = BatteryState{
.percent = percent,
.is_charging = is_charging,
};
EmitEvent();
}
auto Battery::State() -> std::optional<BatteryState> {
@ -94,8 +95,15 @@ auto Battery::State() -> std::optional<BatteryState> {
}
auto Battery::EmitEvent() -> void {
events::System().Dispatch(system_fsm::BatteryStateChanged{});
events::Ui().Dispatch(system_fsm::BatteryStateChanged{});
auto state = state_;
if (!state) {
return;
}
system_fsm::BatteryStateChanged ev{
.new_state = *state,
};
events::System().Dispatch(ev);
events::Ui().Dispatch(ev);
}
} // namespace battery

@ -8,6 +8,7 @@
#include <memory>
#include "battery.hpp"
#include "database.hpp"
#include "service_locator.hpp"
#include "tinyfsm.hpp"
@ -54,7 +55,9 @@ struct HasPhonesChanged : tinyfsm::Event {
};
struct ChargingStatusChanged : tinyfsm::Event {};
struct BatteryStateChanged : tinyfsm::Event {};
struct BatteryStateChanged : tinyfsm::Event {
battery::Battery::BatteryState new_state;
};
struct BluetoothDevicesChanged : tinyfsm::Event {};

@ -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

@ -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

@ -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:

@ -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();

@ -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

@ -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);

@ -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 {

@ -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

@ -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);

@ -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));

@ -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);

@ -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");
}

@ -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_);

@ -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);
}

@ -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

Loading…
Cancel
Save