Files
mayhem-firmware/firmware/application/apps/ui_external_module_view.cpp
T
Mo d72b5ed0b1 Ext Module more than 5 items (#3314)
* Refactor app display to use scrollable menu

Removed specific app name text fields and replaced them with a scrollable menu for an unlimited app list.

* Refactor app display logic in ExternalModuleView

Refactor ExternalModuleView to manage app display more efficiently by using a menu instead of individual text fields.

* Update menu item color to use theme foreground color

* Ext Module: self-heal app list on transient read failures

Only skip rebuilding the scrollable app list when the reported app
count is unchanged AND the current menu already holds that many items.
If some getStandaloneAppInfo() calls failed transiently (e.g. an I2C
read glitch), the menu is incomplete; rebuilding on a later tick lets
it self-heal instead of staying permanently truncated.

Addresses Copilot review feedback on #3314.
2026-09-14 20:53:51 +02:00

129 lines
4.0 KiB
C++

/*
* Copyright (C) 2024 Bernd Herzog
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "ui_external_module_view.hpp"
#include "portapack.hpp"
#include "ui_standalone_view.hpp"
#include "theme.hpp"
#include "i2cdevmanager.hpp"
#include "i2cdev_ppmod.hpp"
#include <optional>
namespace ui {
void ExternalModuleView::focus() {
menu_apps.focus();
}
void ExternalModuleView::on_tick_second() {
i2cdev::I2CDevManager::manual_scan();
auto dev = (i2cdev::I2cDev_PPmod*)i2cdev::I2CDevManager::get_dev_by_model(I2C_DEVMDL::I2CDECMDL_PPMOD);
if (!dev) {
text_header.set("No module connected");
text_name.set("");
text_version.set("");
text_number_apps.set("");
if (shown_count_ != -1) {
menu_apps.clear();
shown_count_ = -1;
}
return;
}
auto device_info = dev->readDeviceInfo();
if (device_info.has_value() == false) {
text_header.set("No module connected");
text_name.set("");
text_version.set("");
text_number_apps.set("");
if (shown_count_ != -1) {
menu_apps.clear();
shown_count_ = -1;
}
return;
}
text_header.set("Module found");
std::string btnText = (std::string) "Module: " + device_info->module_name;
text_name.set(btnText);
text_version.set("Version: " + std::to_string(device_info->module_version));
text_number_apps.set("No# Apps: " + std::to_string(device_info->application_count));
// Only skip the rebuild when the app count is unchanged AND the current
// list is complete. If some getStandaloneAppInfo() calls failed transiently
// (e.g. an I2C read glitch) the menu holds fewer items than reported, so we
// rebuild to let the list self-heal on a later tick.
if ((int32_t)device_info->application_count == shown_count_ &&
menu_apps.item_count() == (size_t)device_info->application_count) {
return;
}
menu_apps.clear();
for (uint32_t i = 0; i < device_info->application_count; i++) {
auto appInfo = dev->getStandaloneAppInfo(i);
if (appInfo.has_value() == false) {
continue;
}
std::string itemText = (std::string) "App " + std::to_string(i + 1) + ": " + (const char*)appInfo->app_name;
switch (appInfo->menu_location) {
case app_location_t::UTILITIES:
itemText += " (Utilities)";
break;
case app_location_t::RX:
itemText += " (RX)";
break;
case app_location_t::TX:
itemText += " (TX)";
break;
case app_location_t::TRX:
itemText += " (TRX)";
break;
case app_location_t::SETTINGS:
itemText += " (Settings)";
break;
case app_location_t::DEBUG:
itemText += " (Debug)";
break;
case app_location_t::HOME:
itemText += " (Home)";
break;
case app_location_t::GAMES:
itemText += " (Games)";
break;
}
menu_apps.add_item({itemText, ui::Theme::getInstance()->fg_light->foreground, nullptr, [](KeyEvent) {}});
}
shown_count_ = (int32_t)device_info->application_count;
}
} // namespace ui