Make title bar a common component, some ui nits

custom
jacqueline 2 years ago
parent 50bb261f67
commit 8eabeedbb9
  1. 1
      src/ui/CMakeLists.txt
  2. 1
      src/ui/include/screen_track_browser.hpp
  3. 2
      src/ui/include/ui_events.hpp
  4. 4
      src/ui/include/ui_fsm.hpp
  5. 30
      src/ui/include/widget_top_bar.hpp
  6. 10
      src/ui/screen_playing.cpp
  7. 24
      src/ui/screen_track_browser.cpp
  8. 9
      src/ui/ui_fsm.cpp
  9. 54
      src/ui/widget_top_bar.cpp

@ -4,6 +4,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"
"splash.c" "font_fusion.c" "font_symbols.c"
INCLUDE_DIRS "include"
REQUIRES "drivers" "lvgl" "tinyfsm" "events" "system_fsm" "database" "esp_timer")

@ -49,6 +49,7 @@ class TrackBrowser : public Screen {
-> std::optional<database::IndexRecord>;
std::weak_ptr<database::Database> db_;
lv_obj_t* back_button_;
lv_obj_t* list_;
lv_obj_t* loading_indicator_;

@ -32,6 +32,8 @@ struct IndexSelected : tinyfsm::Event {
database::IndexInfo index;
};
struct BackPressed : tinyfsm::Event {};
} // namespace internal
} // namespace ui

@ -48,6 +48,7 @@ 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 system_fsm::DisplayReady&) {}
virtual void react(const system_fsm::BootComplete&) {}
@ -83,6 +84,7 @@ class Browse : public UiState {
void react(const internal::RecordSelected&) override;
void react(const internal::IndexSelected&) override;
void react(const internal::BackPressed&) override;
void react(const system_fsm::KeyLockChanged&) override;
void react(const system_fsm::StorageMounted&) override;
@ -93,6 +95,8 @@ class Playing : public UiState {
void entry() override;
void exit() override;
void react(const internal::BackPressed&) override;
void react(const audio::PlaybackStarted&) override;
void react(const audio::PlaybackUpdate&) override;
void react(const audio::QueueUpdate&) override;

@ -0,0 +1,30 @@
/*
* Copyright 2023 jacqueline <me@jacqueline.id.au>
*
* SPDX-License-Identifier: GPL-3.0-only
*/
#pragma once
#include <string>
#include "lvgl.h"
namespace ui {
namespace widgets {
class TopBar {
public:
TopBar(lv_obj_t* parent, lv_group_t* group);
auto set_title(const std::string&) -> void;
lv_obj_t* container_;
lv_obj_t* title_;
lv_obj_t* back_button_;
};
} // namespace widgets
} // namespace ui

@ -37,6 +37,7 @@
#include "track.hpp"
#include "ui_events.hpp"
#include "ui_fsm.hpp"
#include "widget_top_bar.hpp"
#include "widgets/lv_btn.h"
#include "widgets/lv_img.h"
#include "widgets/lv_label.h"
@ -114,6 +115,8 @@ Playing::Playing(std::weak_ptr<database::Database> db, audio::TrackQueue* queue)
lv_obj_set_flex_align(root_, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_START,
LV_FLEX_ALIGN_START);
lv_obj_set_scrollbar_mode(root_, LV_SCROLLBAR_MODE_OFF);
lv_obj_t* above_fold_container = lv_obj_create(root_);
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));
@ -121,11 +124,8 @@ Playing::Playing(std::weak_ptr<database::Database> db, audio::TrackQueue* queue)
lv_obj_set_flex_align(above_fold_container, LV_FLEX_ALIGN_SPACE_BETWEEN,
LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_START);
lv_obj_t* back_button = lv_btn_create(above_fold_container);
lv_obj_set_size(back_button, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
lv_obj_t* back_label = lv_label_create(back_button);
lv_label_set_text(back_label, "<");
lv_group_add_obj(group_, back_button);
widgets::TopBar top_bar(above_fold_container, group_);
top_bar.set_title("Now Playing");
lv_obj_t* info_container = lv_obj_create(above_fold_container);
lv_obj_set_layout(info_container, LV_LAYOUT_FLEX);

@ -31,6 +31,7 @@
#include "screen_track_browser.hpp"
#include "ui_events.hpp"
#include "ui_fsm.hpp"
#include "widget_top_bar.hpp"
#include "widgets/lv_label.h"
static constexpr char kTag[] = "browser";
@ -70,29 +71,17 @@ TrackBrowser::TrackBrowser(
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_START,
LV_FLEX_ALIGN_START);
lv_obj_set_flex_align(root_, 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);
// Wrapping behaves in surprising ways, again due to progressing loading.
lv_group_set_wrap(group_, false);
lv_obj_t* header = lv_obj_create(root_);
lv_obj_set_size(header, lv_pct(100), 15);
lv_obj_set_flex_flow(header, LV_FLEX_FLOW_ROW);
lv_obj_set_flex_align(header, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_START,
LV_FLEX_ALIGN_CENTER);
lv_obj_t* title_label = lv_label_create(header);
lv_label_set_text(title_label, title.c_str());
lv_obj_set_flex_grow(title_label, 1);
lv_obj_t* playback_label = lv_label_create(header);
lv_label_set_text(playback_label, LV_SYMBOL_PAUSE);
lv_obj_t* battery_label = lv_label_create(header);
lv_label_set_text(battery_label, LV_SYMBOL_BATTERY_2);
widgets::TopBar top_bar(root_, group_);
top_bar.set_title(title);
back_button_ = top_bar.back_button_;
list_ = lv_list_create(root_);
lv_obj_set_width(list_, lv_pct(100));
@ -209,6 +198,7 @@ auto TrackBrowser::AddResults(Position pos,
}
lv_group_remove_all_objs(group_);
lv_group_add_obj(group_, back_button_);
int num_children = lv_obj_get_child_cnt(list_);
for (int i = 0; i < num_children; i++) {
lv_group_add_obj(group_, lv_obj_get_child(list_, i));

@ -20,6 +20,7 @@
#include "system_events.hpp"
#include "touchwheel.hpp"
#include "track_queue.hpp"
#include "ui_events.hpp"
namespace ui {
@ -147,6 +148,10 @@ void Browse::react(const internal::IndexSelected& ev) {
std::move(query)));
}
void Browse::react(const internal::BackPressed& ev) {
PopScreen();
}
static std::shared_ptr<screens::Playing> sPlayingScreen;
void Playing::entry() {
@ -171,6 +176,10 @@ void Playing::react(const audio::QueueUpdate& ev) {
sPlayingScreen->OnQueueUpdate();
}
void Playing::react(const internal::BackPressed& ev) {
transit<Browse>();
}
} // namespace states
} // namespace ui

@ -0,0 +1,54 @@
/*
* Copyright 2023 jacqueline <me@jacqueline.id.au>
*
* SPDX-License-Identifier: GPL-3.0-only
*/
#include "widget_top_bar.hpp"
#include "core/lv_group.h"
#include "core/lv_obj.h"
#include "event_queue.hpp"
#include "extra/layouts/flex/lv_flex.h"
#include "ui_events.hpp"
#include "ui_fsm.hpp"
#include "widgets/lv_img.h"
namespace ui {
namespace widgets {
static void back_click_cb(lv_event_t* ev) {
events::Dispatch<internal::BackPressed, UiState>({});
}
TopBar::TopBar(lv_obj_t* parent, lv_group_t* group) {
container_ = lv_obj_create(parent);
lv_obj_set_size(container_, lv_pct(100), 14);
lv_obj_set_flex_flow(container_, LV_FLEX_FLOW_ROW);
lv_obj_set_flex_align(container_, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_START,
LV_FLEX_ALIGN_END);
back_button_ = lv_btn_create(container_);
lv_obj_set_size(back_button_, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
lv_obj_t* button_icon = lv_label_create(back_button_);
lv_label_set_text(button_icon, "<");
lv_group_add_obj(group, back_button_);
lv_obj_add_event_cb(back_button_, back_click_cb, LV_EVENT_CLICKED, NULL);
title_ = lv_label_create(container_);
lv_label_set_text(title_, "");
lv_obj_set_flex_grow(title_, 1);
lv_obj_t* playback_label = lv_label_create(container_);
lv_label_set_text(playback_label, LV_SYMBOL_PAUSE);
lv_obj_t* battery_label = lv_label_create(container_);
lv_label_set_text(battery_label, LV_SYMBOL_BATTERY_2);
}
auto TopBar::set_title(const std::string& new_title) -> void {
lv_label_set_text(title_, new_title.c_str());
}
} // namespace widgets
} // namespace ui
Loading…
Cancel
Save