Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion src/core/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ JsonDocument BruceConfig::toJson() const {
setting["badUSBBLEKeyDelay"] = badUSBBLEKeyDelay;
setting["badUSBBLEShowOutput"] = badUSBBLEShowOutput;

JsonArray pinned = setting["pinnedScripts"].to<JsonArray>();
for (int i = 0; i < pinnedScripts.size(); i++) { pinned.add(pinnedScripts[i]); }

JsonArray dm = setting["disabledMenus"].to<JsonArray>();
for (int i = 0; i < disabledMenus.size(); i++) { dm.add(disabledMenus[i]); }

Expand Down Expand Up @@ -340,7 +343,14 @@ void BruceConfig::fromFile(bool checkFS) {
count++;
log_e("Fail");
}

if (!setting["pinnedScripts"].isNull()) {
pinnedScripts.clear();
JsonArray pinned = setting["pinnedScripts"].as<JsonArray>();
for (JsonVariant e : pinned) { pinnedScripts.push_back(e.as<String>()); }
} else {
count++;
log_e("Fail");
}
if (!setting["wigleBasicToken"].isNull()) {
wigleBasicToken = setting["wigleBasicToken"].as<String>();
} else {
Expand Down Expand Up @@ -712,6 +722,25 @@ void BruceConfig::setStartupAppJSInterpreterFile(String value) {
saveFile();
}

void BruceConfig::addPinnedScript(String path) {
if (!isScriptPinned(path)) {
pinnedScripts.push_back(path);
saveFile();
}
}

void BruceConfig::removePinnedScript(String path) {
auto it = std::find(pinnedScripts.begin(), pinnedScripts.end(), path);
if (it != pinnedScripts.end()) {
pinnedScripts.erase(it);
saveFile();
}
}

bool BruceConfig::isScriptPinned(String path) {
return std::find(pinnedScripts.begin(), pinnedScripts.end(), path) != pinnedScripts.end();
}

void BruceConfig::setWigleBasicToken(String value) {
wigleBasicToken = value;
saveFile();
Expand Down
6 changes: 6 additions & 0 deletions src/core/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,12 @@ class BruceConfig : public BruceTheme {
String startupApp = "";
String startupAppJSInterpreterFile = "";
String wigleBasicToken = "";
std::vector<String> pinnedScripts;

void addPinnedScript(String path);
void removePinnedScript(String path);
bool isScriptPinned(String path);

int devMode = 0;
int colorInverted = 1;
int badUSBBLEKeyboardLayout = 0;
Expand Down
61 changes: 61 additions & 0 deletions src/core/main_menu.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
#include "main_menu.h"
#include "display.h"
#include "main_menu.h"
#include "modules/bjs_interpreter/interpreter.h"
#include "modules/dynamicjs/dynamicjs.h"
#include "utils.h"
#include <LittleFS.h>
#include <globals.h>
#include <vector>

extern String getScriptsFolder(FS *&fs);

MainMenu::MainMenu() {
_menuItems = {
Expand Down Expand Up @@ -35,14 +42,39 @@ MainMenu::MainMenu() {

_totalItems = _menuItems.size();
}
static std::vector<DynamicJSApp *> dynamicHomeApps;
void loadDynamicApps() {
for (auto app : dynamicHomeApps) { delete app; }
dynamicHomeApps.clear();

for (String path : bruceConfig.pinnedScripts) {
FS *appFs = nullptr;

if (SD.exists(path)) {
appFs = &SD;
} else if (LittleFS.exists(path)) {
appFs = &LittleFS;
}

if (appFs != nullptr) {
String nameOnly = path.substring(path.lastIndexOf("/") + 1);
int dotIndex = nameOnly.lastIndexOf(".");
if (dotIndex > 0) { nameOnly = nameOnly.substring(0, dotIndex); }

DynamicJSApp *newApp = new DynamicJSApp(nameOnly, path, appFs);
dynamicHomeApps.push_back(newApp);
}
}
}
MainMenu::~MainMenu() {}

void MainMenu::begin(void) {
returnToMenu = false;
options = {};

std::vector<String> l = bruceConfig.disabledMenus;

// 1. Load all standard firmware apps
for (int i = 0; i < _totalItems; i++) {
String itemName = _menuItems[i]->getName();
if (find(l.begin(), l.end(), itemName) == l.end()) { // If menu item is not disabled
Expand All @@ -69,6 +101,35 @@ void MainMenu::begin(void) {
);
}
}

loadDynamicApps();

for (auto app : dynamicHomeApps) {
String itemName = app->getName();
if (find(l.begin(), l.end(), itemName) == l.end()) {
options.push_back(
{app->getName(),
[app]() { app->optionsMenu(); },
false,
[](void *menuItem, bool shouldRender) {
if (!shouldRender) return false;
drawMainBorder(false);

MenuItemInterface *obj = static_cast<MenuItemInterface *>(menuItem);
float scale = float((float)tftWidth / (float)240);
if (bruceConfigPins.rotation & 0b01) scale = float((float)tftHeight / (float)135);
obj->draw(scale);
#if defined(HAS_TOUCH)
TouchFooter();
#endif
return true;
},
app}
);
}
}
// ----------------------------------------

_currentIndex = loopOptions(options, MENU_TYPE_MAIN, "Main Menu", _currentIndex);
};

Expand Down
1 change: 1 addition & 0 deletions src/core/main_menu.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class MainMenu {
RFMenu rfMenu;
ScriptsMenu scriptsMenu;
WifiMenu wifiMenu;

#if !defined(LITE_VERSION)
LoRaMenu loraMenu;
EthernetMenu ethernetMenu;
Expand Down
2 changes: 2 additions & 0 deletions src/core/menu_items/ConfigMenu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "core/display.h"
#include "core/i2c_finder.h"
#include "core/main_menu.h"
#include "core/sd_functions.h"
#include "core/settings.h"
#include "core/utils.h"
#include "core/wifi/wifi_common.h"
Expand Down Expand Up @@ -168,6 +169,7 @@ void ConfigMenu::systemMenu() {
} },
{"Startup App", [this]() { setStartupApp(); } },
{"Hide/Show Apps", [this]() { mainMenu.hideAppsMenu(); }},
{"Pinned Apps", [this]() { pinnedAppsMenu(); } },
{"Clock", [this]() { setClock(); } },
{"Advanced", [this]() { advancedMenu(); } },
{"Back", []() {} },
Expand Down
64 changes: 64 additions & 0 deletions src/core/settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1194,7 +1194,71 @@ int gsetRfRxPin(bool set) {
returnToMenu = true;
return bruceConfigPins.rfRx;
}
/*********************************************************************
** Function: pinnedAppsMenu
** Manage dynamic JS apps pinned to the main menu
**********************************************************************/
void pinnedAppsMenu() {
while (true) {
std::vector<Option> localOptions;

// 1. Add App to Pin
localOptions.push_back({"Add App to Pin", []() {
FS *fs = &LittleFS;
setupSdCard();
if (sdcardMounted) {
std::vector<Option> fsOpt = {
{"SD Card", [&]() { fs = &SD; } },
{"LittleFS", [&]() { fs = &LittleFS; }},
};
loopOptions(fsOpt, MENU_TYPE_SUBMENU, "Select Storage");
}

String filename = loopSD(*fs, true, "BJS|JS", "/BruceJS");
vTaskDelay(pdMS_TO_TICKS(200));

if (filename != "") { bruceConfig.addPinnedScript(filename); }
}});

localOptions.push_back(
{"Unpin App", []() {
while (true) {
std::vector<Option> unpinOptions;

if (bruceConfig.pinnedScripts.empty()) {
unpinOptions.push_back({"No apps pinned", []() {}});
} else {
for (String path : bruceConfig.pinnedScripts) {
String nameOnly = path.substring(path.lastIndexOf("/") + 1);
unpinOptions.push_back(
{nameOnly, [path]() {
bruceConfig.removePinnedScript(path);

tft.fillScreen(TFT_BLACK);
tft.setTextColor(TFT_ORANGE);
tft.drawCentreString("Unpinned!", tftWidth / 2, tftHeight / 2, 1);
vTaskDelay(pdMS_TO_TICKS(800));
}}
);
}
}

unpinOptions.push_back({"Back", []() {}});

int unpinSelected = loopOptions(unpinOptions, MENU_TYPE_SUBMENU, "Select to Unpin");

if (unpinSelected == -1 || unpinSelected == unpinOptions.size() - 1) { break; }
}
}}
);

localOptions.push_back({"Back", []() {}});

int selected = loopOptions(localOptions, MENU_TYPE_SUBMENU, "Pinned Apps");

if (selected == -1 || selected == localOptions.size() - 1) { return; }
}
}
/*********************************************************************
** Function: setStartupApp
** Handles Menu to set startup app
Expand Down
2 changes: 2 additions & 0 deletions src/core/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ void setWifiStartupConfig();

void setStartupApp();

void pinnedAppsMenu();

void setGpsBaudrateMenu();

void setNetworkCredsMenu();
Expand Down
24 changes: 24 additions & 0 deletions src/modules/dynamicjs/dynamicjs.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#include "./dynamicjs.h"
#include "./modules/bjs_interpreter/interpreter.h"
#include "core/utils.h"
#include <LittleFS.h>

DynamicJSApp::DynamicJSApp(String name, String path, FS *fileSystem) : MenuItemInterface(name) {
filePath = path;
fs = fileSystem;
}

void DynamicJSApp::optionsMenu() { run_bjs_script_headless(*fs, filePath); }

void DynamicJSApp::drawIcon(float scale) {
tft.setTextSize(2 * scale);
tft.setTextColor(TFT_CYAN);
tft.drawCentreString(getName(), tftWidth / 2, tftHeight / 2 - 10, 1);

tft.setTextSize(1 * scale);
tft.setTextColor(TFT_WHITE);
tft.drawCentreString("(JS App)", tftWidth / 2, tftHeight / 2 + 15, 1);
}

bool DynamicJSApp::hasTheme() { return false; }
String DynamicJSApp::themePath() { return ""; }
15 changes: 15 additions & 0 deletions src/modules/dynamicjs/dynamicjs.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#include "MenuItemInterface.h"
#include <FS.h>

class DynamicJSApp : public MenuItemInterface {
public:
String filePath;
FS *fs;

DynamicJSApp(String name, String path, FS *fileSystem);

void optionsMenu() override;
void drawIcon(float scale = 1) override;
bool hasTheme() override;
String themePath() override;
};