diff options
| author | jacqueline <me@jacqueline.id.au> | 2023-11-12 19:14:09 +1100 |
|---|---|---|
| committer | jacqueline <me@jacqueline.id.au> | 2023-11-12 19:14:09 +1100 |
| commit | 8a0a167adbf3d9b6f8b6f16aaf20ca39ad5549de (patch) | |
| tree | 02b6cf23f591915747ec2994381854a79979c4a0 /src | |
| parent | 8471046a95ab9e00f7d42b56dbbc9ce3e5b424b9 (diff) | |
| download | tangara-fw-8a0a167adbf3d9b6f8b6f16aaf20ca39ad5549de.tar.gz | |
Convert the main menu screen to lua lol
Diffstat (limited to 'src')
| -rw-r--r-- | src/app_console/app_console.cpp | 5 | ||||
| -rw-r--r-- | src/database/database.cpp | 4 | ||||
| -rw-r--r-- | src/database/include/database.hpp | 2 | ||||
| -rw-r--r-- | src/drivers/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | src/drivers/include/spiffs.hpp | 15 | ||||
| -rw-r--r-- | src/drivers/spiffs.cpp | 35 | ||||
| -rw-r--r-- | src/lua/CMakeLists.txt | 9 | ||||
| -rw-r--r-- | src/lua/bridge.cpp | 96 | ||||
| -rw-r--r-- | src/lua/include/bridge.hpp | 29 | ||||
| -rw-r--r-- | src/lua/include/lua_thread.hpp | 38 | ||||
| -rw-r--r-- | src/lua/lua_thread.cpp | 98 | ||||
| -rw-r--r-- | src/system_fsm/booting.cpp | 2 | ||||
| -rw-r--r-- | src/ui/CMakeLists.txt | 6 | ||||
| -rw-r--r-- | src/ui/include/screen_lua.hpp | 22 | ||||
| -rw-r--r-- | src/ui/include/screen_menu.hpp | 34 | ||||
| -rw-r--r-- | src/ui/include/ui_events.hpp | 2 | ||||
| -rw-r--r-- | src/ui/include/ui_fsm.hpp | 24 | ||||
| -rw-r--r-- | src/ui/lvgl_task.cpp | 1 | ||||
| -rw-r--r-- | src/ui/screen_lua.cpp | 19 | ||||
| -rw-r--r-- | src/ui/screen_menu.cpp | 75 | ||||
| -rw-r--r-- | src/ui/screen_track_browser.cpp | 1 | ||||
| -rw-r--r-- | src/ui/ui_fsm.cpp | 114 |
22 files changed, 459 insertions, 176 deletions
diff --git a/src/app_console/app_console.cpp b/src/app_console/app_console.cpp index 28fac182..4a57853c 100644 --- a/src/app_console/app_console.cpp +++ b/src/app_console/app_console.cpp @@ -245,7 +245,7 @@ int CmdDbIndex(int argc, char** argv) { } std::shared_ptr<database::Result<database::IndexRecord>> res( - db->GetTracksByIndex(*index, 20).get()); + db->GetTracksByIndex(index->id, 20).get()); int choice_index = 2; if (res->values().empty()) { @@ -708,7 +708,8 @@ void RegisterHapticEffect() { esp_console_cmd_t cmd{ .command = "haptic_effect", .help = - "Plays one, a range of, or all effects from a DRV2624 effect library; run 'haptic_effect help' for more.", + "Plays one, a range of, or all effects from a DRV2624 effect " + "library; run 'haptic_effect help' for more.", .hint = NULL, .func = &CmdHaptics, .argtable = NULL}; diff --git a/src/database/database.cpp b/src/database/database.cpp index e6cb85ed..142735d8 100644 --- a/src/database/database.cpp +++ b/src/database/database.cpp @@ -453,12 +453,12 @@ auto Database::GetIndexes() -> std::vector<IndexInfo> { }; } -auto Database::GetTracksByIndex(const IndexInfo& index, std::size_t page_size) +auto Database::GetTracksByIndex(IndexId index, std::size_t page_size) -> std::future<Result<IndexRecord>*> { return worker_task_->Dispatch<Result<IndexRecord>*>( [=, this]() -> Result<IndexRecord>* { IndexKey::Header header{ - .id = index.id, + .id = index, .depth = 0, .components_hash = 0, }; diff --git a/src/database/include/database.hpp b/src/database/include/database.hpp index fb58f3e7..544e4a62 100644 --- a/src/database/include/database.hpp +++ b/src/database/include/database.hpp @@ -117,7 +117,7 @@ class Database { -> std::future<std::vector<std::shared_ptr<Track>>>; auto GetIndexes() -> std::vector<IndexInfo>; - auto GetTracksByIndex(const IndexInfo& index, std::size_t page_size) + auto GetTracksByIndex(IndexId index, std::size_t page_size) -> std::future<Result<IndexRecord>*>; auto GetTracks(std::size_t page_size) -> std::future<Result<Track>*>; auto GetDump(std::size_t page_size) -> std::future<Result<std::pmr::string>*>; diff --git a/src/drivers/CMakeLists.txt b/src/drivers/CMakeLists.txt index b2b5bfdd..7d1e048d 100644 --- a/src/drivers/CMakeLists.txt +++ b/src/drivers/CMakeLists.txt @@ -5,7 +5,7 @@ idf_component_register( SRCS "touchwheel.cpp" "i2s_dac.cpp" "gpios.cpp" "adc.cpp" "storage.cpp" "i2c.cpp" "spi.cpp" "display.cpp" "display_init.cpp" "samd.cpp" "relative_wheel.cpp" "wm8523.cpp" - "nvs.cpp" "bluetooth.cpp" "haptics.cpp" + "nvs.cpp" "bluetooth.cpp" "haptics.cpp" "spiffs.cpp" INCLUDE_DIRS "include" - REQUIRES "esp_adc" "fatfs" "result" "lvgl" "span" "tasks" "nvs_flash" "bt" "tinyfsm") + REQUIRES "esp_adc" "fatfs" "result" "lvgl" "span" "tasks" "nvs_flash" "bt" "tinyfsm" "spiffs") target_compile_options(${COMPONENT_LIB} PRIVATE ${EXTRA_WARNINGS}) diff --git a/src/drivers/include/spiffs.hpp b/src/drivers/include/spiffs.hpp new file mode 100644 index 00000000..04478590 --- /dev/null +++ b/src/drivers/include/spiffs.hpp @@ -0,0 +1,15 @@ +/* + * Copyright 2023 jacqueline <me@jacqueline.id.au> + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#pragma once + +#include "esp_err.h" + +namespace drivers { + +esp_err_t spiffs_mount(); + +} // namespace drivers diff --git a/src/drivers/spiffs.cpp b/src/drivers/spiffs.cpp new file mode 100644 index 00000000..9a85c0d3 --- /dev/null +++ b/src/drivers/spiffs.cpp @@ -0,0 +1,35 @@ +/* + * Copyright 2023 jacqueline <me@jacqueline.id.au> + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#include "spiffs.hpp" + +#include "esp_err.h" +#include "esp_log.h" +#include "esp_spiffs.h" + +namespace drivers { + +[[maybe_unused]] static constexpr char kTag[] = "spiffs"; + +esp_err_t spiffs_mount() { + esp_vfs_spiffs_conf_t config{ + .base_path = "/lua", + .partition_label = "lua", + .max_files = 5, + .format_if_mount_failed = false, + }; + + esp_err_t res = esp_vfs_spiffs_register(&config); + if (res == ESP_OK) { + size_t total, used; + esp_spiffs_info("lua", &total, &used); + ESP_LOGI(kTag, "spiffs mounted okay. %d / %d ", used / 1024, total / 1024); + } + + return res; +} + +} // namespace drivers diff --git a/src/lua/CMakeLists.txt b/src/lua/CMakeLists.txt new file mode 100644 index 00000000..a2dd8739 --- /dev/null +++ b/src/lua/CMakeLists.txt @@ -0,0 +1,9 @@ +# Copyright 2023 jacqueline <me@jacqueline.id.au> +# +# SPDX-License-Identifier: GPL-3.0-only + +idf_component_register( + SRCS "lua_thread.cpp" "bridge.cpp" + INCLUDE_DIRS "include" + REQUIRES "drivers" "lvgl" "tinyfsm" "events" "system_fsm" "database" "esp_timer" "battery" "esp-idf-lua" "luavgl") +target_compile_options(${COMPONENT_LIB} PRIVATE ${EXTRA_WARNINGS}) diff --git a/src/lua/bridge.cpp b/src/lua/bridge.cpp new file mode 100644 index 00000000..acc64c31 --- /dev/null +++ b/src/lua/bridge.cpp @@ -0,0 +1,96 @@ +/* + * Copyright 2023 jacqueline <me@jacqueline.id.au> + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#include "bridge.hpp" + +#include <memory> +#include <string> + +#include "esp_log.h" +#include "event_queue.hpp" +#include "lua.h" +#include "lua.hpp" +#include "lvgl.h" +#include "service_locator.hpp" +#include "ui_events.hpp" + +namespace lua { + +[[maybe_unused]] static constexpr char kTag[] = "lua_bridge"; +static constexpr char kBridgeKey[] = "bridge"; + +static auto open_settings_fn(lua_State* state) -> int { + events::Ui().Dispatch(ui::internal::ShowSettingsPage{ + .page = ui::internal::ShowSettingsPage::Page::kRoot}); + return 0; +} + +static auto open_now_playing_fn(lua_State* state) -> int { + events::Ui().Dispatch(ui::internal::ShowNowPlaying{}); + return 0; +} + +static auto open_browse_fn(lua_State* state) -> int { + int index = luaL_checkinteger(state, 1); + events::Ui().Dispatch(ui::internal::IndexSelected{ + .id = static_cast<uint8_t>(index), + }); + return 0; +} + +static const struct luaL_Reg kLegacyUiFuncs[] = { + {"open_settings", open_settings_fn}, + {"open_now_playing", open_now_playing_fn}, + {"open_browse", open_browse_fn}, + {NULL, NULL}}; + +static auto lua_legacy_ui(lua_State* state) -> int { + luaL_newlib(state, kLegacyUiFuncs); + return 1; +} + +static auto get_indexes(lua_State* state) -> int { + lua_pushstring(state, kBridgeKey); + lua_gettable(state, LUA_REGISTRYINDEX); + Bridge* instance = reinterpret_cast<Bridge*>(lua_touserdata(state, -1)); + + lua_newtable(state); + + auto db = instance->services().database().lock(); + if (!db) { + return 1; + } + + for (const auto& i : db->GetIndexes()) { + lua_pushstring(state, i.name.c_str()); + lua_rawseti(state, -2, i.id); + } + + return 1; +} + +static const struct luaL_Reg kDatabaseFuncs[] = {{"get_indexes", get_indexes}, + {NULL, NULL}}; + +static auto lua_database(lua_State* state) -> int { + luaL_newlib(state, kDatabaseFuncs); + return 1; +} + +Bridge::Bridge(system_fsm::ServiceLocator& services, lua_State& s) + : services_(services), state_(s) { + lua_pushstring(&s, kBridgeKey); + lua_pushlightuserdata(&s, this); + lua_settable(&s, LUA_REGISTRYINDEX); + + luaL_requiref(&s, "legacy_ui", lua_legacy_ui, true); + lua_pop(&s, 1); + + luaL_requiref(&s, "database", lua_database, true); + lua_pop(&s, 1); +} + +} // namespace lua diff --git a/src/lua/include/bridge.hpp b/src/lua/include/bridge.hpp new file mode 100644 index 00000000..059d0604 --- /dev/null +++ b/src/lua/include/bridge.hpp @@ -0,0 +1,29 @@ +/* + * Copyright 2023 jacqueline <me@jacqueline.id.au> + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#pragma once + +#include <memory> +#include <string> + +#include "lua.hpp" +#include "lvgl.h" +#include "service_locator.hpp" + +namespace lua { + +class Bridge { + public: + Bridge(system_fsm::ServiceLocator&, lua_State& s); + + system_fsm::ServiceLocator& services() { return services_; } + + private: + system_fsm::ServiceLocator& services_; + lua_State& state_; +}; + +} // namespace lua diff --git a/src/lua/include/lua_thread.hpp b/src/lua/include/lua_thread.hpp new file mode 100644 index 00000000..381b1bdb --- /dev/null +++ b/src/lua/include/lua_thread.hpp @@ -0,0 +1,38 @@ +/* + * Copyright 2023 jacqueline <me@jacqueline.id.au> + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#pragma once + +#include <memory> +#include <string> + +#include "lua.hpp" +#include "lvgl.h" + +#include "bridge.hpp" +#include "service_locator.hpp" + +namespace lua { + +class Allocator; + +class LuaThread { + public: + static auto Start(system_fsm::ServiceLocator&, lv_obj_t* lvgl_root = nullptr) + -> LuaThread*; + ~LuaThread(); + + auto RunScript(const std::string& path) -> bool; + + private: + LuaThread(std::unique_ptr<Allocator>&, std::unique_ptr<Bridge>&, lua_State*); + + std::unique_ptr<Allocator> alloc_; + std::unique_ptr<Bridge> bridge_; + lua_State* state_; +}; + +} // namespace lua diff --git a/src/lua/lua_thread.cpp b/src/lua/lua_thread.cpp new file mode 100644 index 00000000..cb7066a5 --- /dev/null +++ b/src/lua/lua_thread.cpp @@ -0,0 +1,98 @@ +/* + * Copyright 2023 jacqueline <me@jacqueline.id.au> + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#include "lua_thread.hpp" +#include <memory> + +#include "esp_heap_caps.h" +#include "esp_log.h" +#include "lua.h" +#include "lua.hpp" +#include "luavgl.h" +#include "service_locator.hpp" + +namespace lua { + +[[maybe_unused]] static constexpr char kTag[] = "lua"; + +class Allocator { + public: + Allocator() : total_allocated_(0) {} + + auto alloc(void* ptr, size_t osize, size_t nsize) -> void* { + total_allocated_ = total_allocated_ - osize + nsize; + // ESP_LOGI(kTag, "lua realloc -> %u KiB", total_allocated_ / 1024); + if (nsize == 0) { + heap_caps_free(ptr); + return NULL; + } else { + return heap_caps_realloc(ptr, nsize, MALLOC_CAP_SPIRAM); + } + } + + private: + size_t total_allocated_; +}; + +static auto lua_alloc(void* ud, void* ptr, size_t osize, size_t nsize) + -> void* { + Allocator* instance = reinterpret_cast<Allocator*>(ud); + return instance->alloc(ptr, osize, nsize); +} + +static int lua_panic(lua_State* L) { + ESP_LOGE(kTag, "!! PANIC !! %s", lua_tostring(L, -1)); + return 0; +} + +auto LuaThread::Start(system_fsm::ServiceLocator& services, lv_obj_t* lvgl_root) + -> LuaThread* { + auto alloc = std::make_unique<Allocator>(); + lua_State* state = lua_newstate(lua_alloc, alloc.get()); + if (!state) { + return nullptr; + } + + luaL_openlibs(state); + lua_atpanic(state, lua_panic); + + auto bridge = std::make_unique<Bridge>(services, *state); + + // FIXME: luavgl init should probably be a part of the bridge. + if (lvgl_root) { + luavgl_set_root(state, lvgl_root); + luaL_requiref(state, "lvgl", luaopen_lvgl, true); + lua_pop(state, 1); + } + + return new LuaThread(alloc, bridge, state); +} + +LuaThread::LuaThread(std::unique_ptr<Allocator>& alloc, + std::unique_ptr<Bridge>& bridge, + lua_State* state) + : alloc_(std::move(alloc)), bridge_(std::move(bridge)), state_(state) {} + +LuaThread::~LuaThread() { + lua_close(state_); +} + +auto LuaThread::RunScript(const std::string& path) -> bool { + int res = luaL_loadfilex(state_, path.c_str(), NULL); + if (res != LUA_OK) { + return false; + } + res = lua_pcall(state_, 0, 0, 0); + if (res) { + const char* msg = lua_tostring(state_, -1); + lua_writestring(msg, strlen(msg)); + lua_writeline(); + lua_pop(state_, 1); + } + return true; +} + +} // namespace lua diff --git a/src/system_fsm/booting.cpp b/src/system_fsm/booting.cpp index 53288dbd..e7080e9b 100644 --- a/src/system_fsm/booting.cpp +++ b/src/system_fsm/booting.cpp @@ -6,6 +6,7 @@ #include "collation.hpp" #include "haptics.hpp" +#include "spiffs.hpp" #include "system_fsm.hpp" #include <stdint.h> @@ -71,6 +72,7 @@ auto Booting::entry() -> void { tasks::Worker::Start<tasks::Type::kBackgroundWorker>()}); ESP_LOGI(kTag, "installing remaining drivers"); + drivers::spiffs_mount(); sServices->samd(std::unique_ptr<drivers::Samd>(drivers::Samd::Create())); sServices->nvs( std::unique_ptr<drivers::NvsStorage>(drivers::NvsStorage::OpenSync())); diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index 8d3640e6..00b1f1f5 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -3,15 +3,15 @@ # SPDX-License-Identifier: GPL-3.0-only idf_component_register( - SRCS "lvgl_task.cpp" "ui_fsm.cpp" "screen_splash.cpp" "screen_menu.cpp" + SRCS "lvgl_task.cpp" "ui_fsm.cpp" "screen_splash.cpp" "encoder_input.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" "screen_settings.cpp" - "event_binding.cpp" "modal_add_to_queue.cpp" + "event_binding.cpp" "modal_add_to_queue.cpp" "screen_lua.cpp" "splash.c" "font_fusion.c" "font_symbols.c" "icons/battery_empty.c" "icons/battery_full.c" "icons/battery_20.c" "icons/battery_40.c" "icons/battery_60.c" "icons/battery_80.c" "icons/play.c" "icons/pause.c" "icons/bluetooth.c" INCLUDE_DIRS "include" - REQUIRES "drivers" "lvgl" "tinyfsm" "events" "system_fsm" "database" "esp_timer" "battery" "bindey") + REQUIRES "drivers" "lvgl" "tinyfsm" "events" "system_fsm" "database" "esp_timer" "battery" "bindey" "lua" "luavgl") target_compile_options(${COMPONENT_LIB} PRIVATE ${EXTRA_WARNINGS}) diff --git a/src/ui/include/screen_lua.hpp b/src/ui/include/screen_lua.hpp new file mode 100644 index 00000000..df83ea8b --- /dev/null +++ b/src/ui/include/screen_lua.hpp @@ -0,0 +1,22 @@ +/* + * Copyright 2023 jacqueline <me@jacqueline.id.au> + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#pragma once + +#include "lua.hpp" + +#include "screen.hpp" + +namespace ui { +namespace screens { + +class Lua : public Screen { + public: + explicit Lua(lua_State* l); +}; + +} // namespace screens +} // namespace ui diff --git a/src/ui/include/screen_menu.hpp b/src/ui/include/screen_menu.hpp deleted file mode 100644 index a83346f6..00000000 --- a/src/ui/include/screen_menu.hpp +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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 "model_top_bar.hpp" -#include "screen.hpp" -#include "screen_settings.hpp" - -namespace ui { -namespace screens { - -class Menu : public MenuScreen { - public: - explicit Menu(models::TopBar&, std::vector<database::IndexInfo> indexes); - ~Menu(); - - private: - std::vector<database::IndexInfo> indexes_; - lv_obj_t* container_; - lv_obj_t* label_; -}; - -} // namespace screens -} // namespace ui diff --git a/src/ui/include/ui_events.hpp b/src/ui/include/ui_events.hpp index 2bee6222..b8dd459c 100644 --- a/src/ui/include/ui_events.hpp +++ b/src/ui/include/ui_events.hpp @@ -35,7 +35,7 @@ struct RecordSelected : tinyfsm::Event { }; struct IndexSelected : tinyfsm::Event { - database::IndexInfo index; + database::IndexId id; }; struct ControlSchemeChanged : tinyfsm::Event {}; diff --git a/src/ui/include/ui_fsm.hpp b/src/ui/include/ui_fsm.hpp index da63b77f..7d1d62d6 100644 --- a/src/ui/include/ui_fsm.hpp +++ b/src/ui/include/ui_fsm.hpp @@ -16,6 +16,7 @@ #include "bindey/property.h" #include "db_events.hpp" #include "gpios.hpp" +#include "lua_thread.hpp" #include "lvgl_task.hpp" #include "model_playback.hpp" #include "model_top_bar.hpp" @@ -89,7 +90,7 @@ class UiState : public tinyfsm::Fsm<UiState> { protected: void PushScreen(std::shared_ptr<Screen>); - void PopScreen(); + int PopScreen(); static std::unique_ptr<UiTask> sTask; static std::shared_ptr<system_fsm::ServiceLocator> sServices; @@ -99,6 +100,9 @@ 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; + static std::shared_ptr<lua::LuaThread> sLua; + + static std::weak_ptr<screens::Bluetooth> bluetooth_screen_; static models::Playback sPlaybackModel; static models::TopBar sTopBarModel; @@ -110,6 +114,19 @@ class Splash : public UiState { public: void exit() override; void react(const system_fsm::BootComplete&) override; + void react(const system_fsm::StorageMounted&) override; + using UiState::react; +}; + +class Lua : public UiState { + public: + void entry() override; + void exit() override; + + void react(const internal::IndexSelected&) override; + void react(const internal::ShowNowPlaying&) override; + void react(const internal::ShowSettingsPage&) override; + using UiState::react; }; @@ -131,20 +148,15 @@ class Browse : public UiState { void entry() override; void react(const internal::RecordSelected&) override; - void react(const internal::IndexSelected&) override; void react(const internal::BackPressed&) override; void react(const internal::ShowNowPlaying&) override; void react(const internal::ShowSettingsPage&) override; void react(const internal::ReindexDatabase&) override; - void react(const system_fsm::StorageMounted&) override; void react(const system_fsm::BluetoothDevicesChanged&) override; using UiState::react; - - private: - std::weak_ptr<screens::Bluetooth> bluetooth_screen_; }; class Playing : public UiState { diff --git a/src/ui/lvgl_task.cpp b/src/ui/lvgl_task.cpp index 817ed185..96f9bdf5 100644 --- a/src/ui/lvgl_task.cpp +++ b/src/ui/lvgl_task.cpp @@ -30,6 +30,7 @@ #include "hal/gpio_types.h" #include "hal/lv_hal_indev.h" #include "hal/spi_types.h" +#include "lua.h" #include "lv_api_map.h" #include "lvgl/lvgl.h" #include "misc/lv_color.h" diff --git a/src/ui/screen_lua.cpp b/src/ui/screen_lua.cpp new file mode 100644 index 00000000..cee5186e --- /dev/null +++ b/src/ui/screen_lua.cpp @@ -0,0 +1,19 @@ +/* + * Copyright 2023 jacqueline <me@jacqueline.id.au> + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#include "screen_lua.hpp" + +#include "lua.hpp" +#include "luavgl.h" + +namespace ui { +namespace screens { + +Lua::Lua(lua_State* l) { +} + +} // namespace screens +} // namespace ui diff --git a/src/ui/screen_menu.cpp b/src/ui/screen_menu.cpp deleted file mode 100644 index 037e1156..00000000 --- a/src/ui/screen_menu.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2023 jacqueline <me@jacqueline.id.au> - * - * SPDX-License-Identifier: GPL-3.0-only - */ - -#include "screen_menu.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 "lv_api_map.h" -#include "misc/lv_area.h" -#include "model_top_bar.hpp" -#include "ui_events.hpp" -#include "ui_fsm.hpp" -#include "widget_top_bar.hpp" -#include "widgets/lv_label.h" - -namespace ui { -namespace screens { - -static void now_playing_click_cb(lv_event_t* ev) { - events::Ui().Dispatch(internal::ShowNowPlaying{}); -} - -static void settings_click_callback(lv_event_t* ev) { - events::Ui().Dispatch(internal::ShowSettingsPage{ - .page = internal::ShowSettingsPage::Page::kRoot}); -} - -static void index_click_cb(lv_event_t* ev) { - if (ev->user_data == NULL) { - return; - } - database::IndexInfo* index = - reinterpret_cast<database::IndexInfo*>(ev->user_data); - - events::Ui().Dispatch(internal::IndexSelected{.index = *index}); -} - -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)); - - lv_obj_t* now_playing = lv_list_add_btn(list, NULL, "Now Playing"); - lv_obj_add_event_cb(now_playing, now_playing_click_cb, LV_EVENT_CLICKED, - NULL); - lv_group_add_obj(group_, now_playing); - - for (database::IndexInfo& index : indexes_) { - lv_obj_t* item = lv_list_add_btn(list, NULL, index.name.c_str()); - lv_obj_add_event_cb(item, index_click_cb, LV_EVENT_CLICKED, &index); - lv_group_add_obj(group_, item); - } - - lv_obj_t* settings = lv_list_add_btn(list, NULL, "Settings"); - lv_obj_add_event_cb(settings, settings_click_callback, LV_EVENT_CLICKED, - NULL); - lv_group_add_obj(group_, settings); -} - -Menu::~Menu() {} - -} // namespace screens -} // namespace ui diff --git a/src/ui/screen_track_browser.cpp b/src/ui/screen_track_browser.cpp index 34abf17e..c7b035ad 100644 --- a/src/ui/screen_track_browser.cpp +++ b/src/ui/screen_track_browser.cpp @@ -18,7 +18,6 @@ #include "misc/lv_anim.h" #include "misc/lv_color.h" #include "model_top_bar.hpp" -#include "screen_menu.hpp" #include "core/lv_event.h" #include "esp_log.h" diff --git a/src/ui/ui_fsm.cpp b/src/ui/ui_fsm.cpp index 8d3fa20d..748e08f9 100644 --- a/src/ui/ui_fsm.cpp +++ b/src/ui/ui_fsm.cpp @@ -10,9 +10,16 @@ #include "audio_fsm.hpp" #include "battery.hpp" +#include "core/lv_group.h" #include "core/lv_obj.h" +#include "core/lv_obj_tree.h" #include "database.hpp" +#include "esp_heap_caps.h" #include "haptics.hpp" +#include "lauxlib.h" +#include "lua.hpp" +#include "lua_thread.hpp" +#include "luavgl.h" #include "misc/lv_gc.h" #include "audio_events.hpp" @@ -28,19 +35,21 @@ #include "nvs.hpp" #include "relative_wheel.hpp" #include "screen.hpp" -#include "screen_menu.hpp" +#include "screen_lua.hpp" #include "screen_onboarding.hpp" #include "screen_playing.hpp" #include "screen_settings.hpp" #include "screen_splash.hpp" #include "screen_track_browser.hpp" #include "source.hpp" +#include "spiffs.hpp" #include "storage.hpp" #include "system_events.hpp" #include "touchwheel.hpp" #include "track_queue.hpp" #include "ui_events.hpp" #include "widget_top_bar.hpp" +#include "widgets/lv_label.h" namespace ui { @@ -56,6 +65,9 @@ std::shared_ptr<EncoderInput> UiState::sInput; std::stack<std::shared_ptr<Screen>> UiState::sScreens; std::shared_ptr<Screen> UiState::sCurrentScreen; std::shared_ptr<Modal> UiState::sCurrentModal; +std::shared_ptr<lua::LuaThread> UiState::sLua; + +std::weak_ptr<screens::Bluetooth> UiState::bluetooth_screen_; models::Playback UiState::sPlaybackModel; models::TopBar UiState::sTopBarModel{{}, @@ -83,12 +95,13 @@ void UiState::PushScreen(std::shared_ptr<Screen> screen) { sCurrentScreen = screen; } -void UiState::PopScreen() { +int UiState::PopScreen() { if (sScreens.empty()) { - return; + return 0; } sCurrentScreen = sScreens.top(); sScreens.pop(); + return sScreens.size(); } void UiState::react(const system_fsm::KeyLockChanged& ev) { @@ -159,12 +172,48 @@ void Splash::react(const system_fsm::BootComplete& ev) { } else { ESP_LOGE(kTag, "no input devices initialised!"); } +} - if (sServices->nvs().HasShownOnboarding()) { - transit<Browse>(); - } else { - transit<Onboarding>(); +void Splash::react(const system_fsm::StorageMounted&) { + transit<Lua>(); +} + +void Lua::entry() { + if (!sLua) { + sCurrentScreen.reset(new Screen()); + lv_group_set_default(sCurrentScreen->group()); + + sLua.reset(lua::LuaThread::Start(*sServices, sCurrentScreen->content())); + sLua->RunScript("/lua/main.lua"); + + lv_group_set_default(NULL); + } +} + +void Lua::exit() {} + +void Lua::react(const internal::IndexSelected& ev) { + auto db = sServices->database().lock(); + if (!db) { + return; } + + ESP_LOGI(kTag, "selected index %u", ev.id); + auto query = db->GetTracksByIndex(ev.id, kRecordsPerPage); + std::pmr::vector<std::pmr::string> crumbs = {""}; + PushScreen(std::make_shared<screens::TrackBrowser>( + sTopBarModel, sServices->track_queue(), sServices->database(), crumbs, + std::move(query))); + transit<Browse>(); +} + +void Lua::react(const internal::ShowNowPlaying&) { + transit<Playing>(); +} + +void Lua::react(const internal::ShowSettingsPage& ev) { + PushScreen(std::shared_ptr<Screen>(new screens::Settings(sTopBarModel))); + transit<Browse>(); } void Onboarding::entry() { @@ -218,31 +267,7 @@ void Onboarding::react(const internal::OnboardingNavigate& ev) { } } -static bool sBrowseFirstEntry = true; - -void Browse::entry() { - if (sBrowseFirstEntry) { - auto db = sServices->database().lock(); - if (!db) { - return; - } - sCurrentScreen = - std::make_shared<screens::Menu>(sTopBarModel, db->GetIndexes()); - sBrowseFirstEntry = false; - } -} - -void Browse::react(const system_fsm::StorageMounted& ev) { - if (sBrowseFirstEntry) { - auto db = sServices->database().lock(); - if (!db) { - return; - } - sCurrentScreen = - std::make_shared<screens::Menu>(sTopBarModel, db->GetIndexes()); - sBrowseFirstEntry = false; - } -} +void Browse::entry() {} void Browse::react(const internal::ShowNowPlaying& ev) { transit<Playing>(); @@ -327,22 +352,10 @@ void Browse::react(const internal::RecordSelected& ev) { } } -void Browse::react(const internal::IndexSelected& ev) { - auto db = sServices->database().lock(); - if (!db) { - return; - } - - ESP_LOGI(kTag, "selected index %s", ev.index.name.c_str()); - auto query = db->GetTracksByIndex(ev.index, kRecordsPerPage); - std::pmr::vector<std::pmr::string> crumbs = {ev.index.name}; - PushScreen(std::make_shared<screens::TrackBrowser>( - sTopBarModel, sServices->track_queue(), sServices->database(), crumbs, - std::move(query))); -} - void Browse::react(const internal::BackPressed& ev) { - PopScreen(); + if (PopScreen() == 0) { + transit<Lua>(); + } } void Browse::react(const system_fsm::BluetoothDevicesChanged&) { @@ -368,11 +381,14 @@ void Playing::entry() { void Playing::exit() { sPlayingScreen.reset(); - PopScreen(); } void Playing::react(const internal::BackPressed& ev) { - transit<Browse>(); + if (PopScreen() == 0) { + transit<Lua>(); + } else { + transit<Browse>(); + } } static std::shared_ptr<modals::Progress> sIndexProgress; |
