diff --git a/firmware/application/ui/ui_btngrid.cpp b/firmware/application/ui/ui_btngrid.cpp index 8ab4615c2..b1379df5a 100644 --- a/firmware/application/ui/ui_btngrid.cpp +++ b/firmware/application/ui/ui_btngrid.cpp @@ -26,6 +26,7 @@ #include "ui_btngrid.hpp" #include "rtc_time.hpp" +#include "sd_card.hpp" namespace ui { @@ -143,6 +144,7 @@ void BtnGridView::clear() { // clear vector and release memory, not using swap since it's causing capture to glitch/fault menu_items.clear(); + // TODO(u-foka): Clean up my mess, move this somewhere to clear memory when the view is not visible, but not to be confused with clearing the menu items... for (auto& item : menu_item_views) remove_child(item.get()); @@ -198,6 +200,15 @@ void BtnGridView::show_hide_arrows() { } } +void BtnGridView::reload_items() { + menu_items.clear(); + on_populate(); + set_highlighted(highlighted_item, true); + show_hide_arrows(); + + set_dirty(); // Redraw the now potentially empty space as well +} + void BtnGridView::update_items() { size_t i = 0; @@ -237,7 +248,7 @@ void BtnGridView::show_arrows_enabled(bool enabled) { } } -bool BtnGridView::set_highlighted(int32_t new_value) { +bool BtnGridView::set_highlighted(int32_t new_value, bool force_update) { int32_t item_count = (int32_t)menu_items.size(); if (new_value < 0) @@ -247,13 +258,15 @@ bool BtnGridView::set_highlighted(int32_t new_value) { new_value = item_count - 1; } + bool needs_update = false; + if (((uint32_t)new_value > offset) && ((new_value - offset) >= displayed_max)) { // Shift BtnGridView up highlighted_item = new_value; // rounding up new offset to next multiple of rows offset = new_value - displayed_max + rows_; offset -= (offset % rows_); - update_items(); + needs_update = true; // refresh whole screen (display flickers) only if scrolling last row up and a blank button is needed at the bottom if ((new_value + rows_ >= item_count) && (item_count % rows_) != 0) set_dirty(); @@ -261,13 +274,23 @@ bool BtnGridView::set_highlighted(int32_t new_value) { // Shift BtnGridView down highlighted_item = new_value; offset = (new_value / rows_) * rows_; - update_items(); + needs_update = true; // no need to set_dirty() here since all buttons have been repainted } else { // Just update highlight highlighted_item = new_value; } + // Normalize offset to show maximum items when count decreased + if (offset + displayed_max > item_count && item_count > 0) { + offset = (item_count >= displayed_max) ? item_count - displayed_max : 0; + needs_update = true; + } + + if (needs_update || force_update) { + update_items(); + } + if (visible()) item_view(highlighted_item - offset)->focus(); @@ -292,12 +315,18 @@ void BtnGridView::on_blur() { } void BtnGridView::on_show() { - on_populate(); View::on_show(); - set_highlighted(highlighted_item); + + sd_card_status_signal_token = sd_card::status_signal += [this](const sd_card::Status /*status*/) { + this->reload_items(); + }; + + reload_items(); } void BtnGridView::on_hide() { + sd_card::status_signal -= sd_card_status_signal_token; + View::on_hide(); clear(); set_arrow_up_enabled(false); diff --git a/firmware/application/ui/ui_btngrid.hpp b/firmware/application/ui/ui_btngrid.hpp index a4a0be1f7..de0ad6c51 100644 --- a/firmware/application/ui/ui_btngrid.hpp +++ b/firmware/application/ui/ui_btngrid.hpp @@ -71,7 +71,7 @@ class BtnGridView : public View { bool show_arrows{true}; // flag used to hide arrows in main menu void show_arrows_enabled(bool enabled); - bool set_highlighted(int32_t new_value); + bool set_highlighted(int32_t new_value, bool force_update = false); uint32_t highlighted_index(); void set_parent_rect(const Rect new_parent_rect) override; @@ -88,6 +88,7 @@ class BtnGridView : public View { bool on_encoder(const EncoderEvent event) override; bool blacklisted_app(GridItem new_item); + void reload_items(); void update_items(); void set_btn_height_fixed(uint8_t h) { button_h = h; @@ -116,6 +117,7 @@ class BtnGridView : public View { size_t displayed_max{0}; size_t highlighted_item{0}; size_t offset{0}; + SignalToken sd_card_status_signal_token{}; }; } /* namespace ui */ diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index 556410071..6ecef1b4f 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -771,8 +771,6 @@ void add_apps(NavigationView& nav, BtnGridView& grid, app_location_t loc) { true); } }; - - grid.update_items(); } // clang-format off @@ -789,7 +787,7 @@ void add_external_items(NavigationView& nav, app_location_t location, BtnGridVie "Check SD card\n" "Update SD card content\n"); }}, - error_tile_pos); + error_tile_pos, true); } else { std::sort(externalItems.begin(), externalItems.end(), [](const auto &a, const auto &b) { @@ -804,8 +802,6 @@ void add_external_items(NavigationView& nav, app_location_t location, BtnGridVie } } - - grid.update_items(); } } // clang-format on @@ -824,7 +820,8 @@ ReceiversMenuView::ReceiversMenuView(NavigationView& nav) void ReceiversMenuView::on_populate() { bool return_icon = pmem::show_gui_return_icon(); if (return_icon) { - add_item({"..", Theme::getInstance()->fg_light->foreground, &bitmap_icon_previous, [this]() { nav_.pop(); }}); + add_item({"..", Theme::getInstance()->fg_light->foreground, &bitmap_icon_previous, [this]() { nav_.pop(); }}, + true); } add_apps(nav_, *this, RX); add_external_items(nav_, app_location_t::RX, *this, return_icon ? 1 : 0); @@ -913,14 +910,15 @@ SystemMenuView::SystemMenuView(NavigationView& nav) } void SystemMenuView::on_populate() { - if (!verify_sdcard_format()) { - add_item({"SDCard Error", Theme::getInstance()->error_dark->foreground, nullptr, [this]() { - nav_.display_modal("Error", "SD Card is not exFAT/FAT32"); - }}); - } add_apps(nav_, *this, HOME); add_external_items(nav_, app_location_t::HOME, *this, 0); add_item({"HackRF", Theme::getInstance()->fg_cyan->foreground, &bitmap_icon_hackrf, [this]() { hackrf_mode(nav_); }}); + if (!verify_sdcard_format()) { // Moved to the end... after sd status change event, fstype wasn't populated fast enough.. + insert_item({"SDCard Error", Theme::getInstance()->error_dark->foreground, nullptr, [this]() { + nav_.display_modal("Error", "SD Card is not exFAT/FAT32"); + }}, + 0, true); + } } /* SystemView ************************************************************/