Skip to content

Commit

Permalink
[WIP] Refactor launcher and add overlay support.
Browse files Browse the repository at this point in the history
Refactored the launcher to improve app management and GUI updates. Introduced a new overlay module for modular GUI management and cleaner element handling. Added error handling for GUI element management and updated battery level calculation logic.
  • Loading branch information
Charles-Mahoudeau committed Aug 16, 2024
1 parent 61b5644 commit 5267594
Show file tree
Hide file tree
Showing 10 changed files with 435 additions and 52 deletions.
46 changes: 46 additions & 0 deletions lib/applications/src/app.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,52 @@ namespace AppManager {
StandbyMode::wait();
}

void update() {
threadsync.lock();

// Run tick on every app
for (const auto& app: appList) {
if (app->isRunning()) {
app->luaInstance->loop();
} else if (app->luaInstance != nullptr) {
app->kill();
}
}

// Update foreground app GUI
// TODO : What happens if a background app is on top of a foreground app on the stack ?
if (!appStack.empty()) {
const App* app = appStack.back();

if (app->luaInstance != nullptr) {
app->luaInstance->lua_gui.update();
}
}

threadsync.unlock();
}

void quitApp() {
if (appStack.empty()) {
throw libsystem::exceptions::RuntimeError("Cannot quit an app if no app is running.");
}

// Get the currently running app
App* app = appStack.back();

// Check if the app on the top is a foreground app
// TODO : Go down the stack ?
if (app->background) {
throw libsystem::exceptions::RuntimeError("Cannot quit an backgroundn app.");
}

// Kill the app
app->kill();

// Remove app from stack
appStack.pop_back();
}

bool isAnyVisibleApp() {
return !appStack.empty();
}
Expand Down
14 changes: 14 additions & 0 deletions lib/applications/src/app.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,22 @@ namespace AppManager
bool isAnyVisibleApp();

void init();

/**
* @deprecated
*/
void loop();

/**
* Update every application.
*/
void update();

/**
* Quit the currently foreground running application.
*/
void quitApp();

void event_oncall();
void event_onlowbattery();
void event_oncharging();
Expand Down
196 changes: 195 additions & 1 deletion lib/applications/src/launcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

#include <app.hpp>
#include <gsm.hpp>
#include <libsystem.hpp>
#include <memory>

std::string getFormatedHour()
{
Expand All @@ -16,6 +18,198 @@ std::string getFormatedHour()
return dayName + " " + std::to_string(GSM::days) + " " + monthName;
}

namespace applications::launcher {
std::shared_ptr<Window> launcherWindow = nullptr;
std::map<gui::ElementBase*, std::shared_ptr<AppManager::App>> applicationsIconsMap;
std::shared_ptr<AppManager::App> targetApp = nullptr;

bool allocated = false;
bool dirty = true;

Label* clockLabel = nullptr;
Label* dateLabel = nullptr;
Label* batteryLabel = nullptr;

uint64_t lastClockUpdate = 0;
uint64_t lastBatteryUpdate = 0;
}

void applications::launcher::init() {
launcherWindow = std::make_shared<Window>();
}

void applications::launcher::update() {
libsystem::log("applications::launcher::update");

if (dirty) {
// If dirty, free to force redraw it
free();
}

if (!allocated) {
// If launcher has been freed, redraw it
draw();
}

// Update, draw AND update touch events
launcherWindow->updateAll();

// Check touch events
targetApp = nullptr;

for (const auto& [icon, app] : applicationsIconsMap) {
if (icon->isTouched()) {
targetApp = app;
}
}

// Update dynamic elements
// TODO : Refactor this
if (millis() > lastClockUpdate + 1000) {
// What ???
static int min;

if(min != GSM::minutes) {
clockLabel->setText(std::to_string(GSM::hours) + ":" + (GSM::minutes<=9 ? "0" : "") + std::to_string(GSM::minutes));
dateLabel->setText(getFormatedHour());

min = GSM::minutes;
}

lastClockUpdate = millis();
}
if (millis() > lastBatteryUpdate + 10000) {
batteryLabel->setText(std::to_string(static_cast<int>(GSM::getBatteryLevel() * 100)) + "%");

lastBatteryUpdate = millis();
}
}

void applications::launcher::draw() {
libsystem::log("applications::launcher::draw");

StandbyMode::triggerPower();

// Clock
clockLabel = new Label(86, 42, 148, 41);
clockLabel->setText(std::to_string(GSM::hours) + ":" + (GSM::minutes<=9 ? "0" : "") + std::to_string(GSM::minutes)); // hour
clockLabel->setVerticalAlignment(Label::Alignement::CENTER);
clockLabel->setHorizontalAlignment(Label::Alignement::CENTER);
clockLabel->setFontSize(36);
launcherWindow->addChild(clockLabel);

// Date
dateLabel = new Label(55, 89, 210, 18);
dateLabel->setText(getFormatedHour());
dateLabel->setVerticalAlignment(Label::Alignement::CENTER);
dateLabel->setHorizontalAlignment(Label::Alignement::CENTER);
dateLabel->setFontSize(16);
launcherWindow->addChild(dateLabel);

// Battery
batteryLabel = new Label(269, 10, 40, 18);
batteryLabel->setText(std::to_string(static_cast<int>(GSM::getBatteryLevel() * 100)) + "%");
batteryLabel->setVerticalAlignment(Label::Alignement::CENTER);
batteryLabel->setHorizontalAlignment(Label::Alignement::CENTER);
batteryLabel->setFontSize(18);
launcherWindow->addChild(batteryLabel);

// Network
if(GSM::getNetworkStatus() == 99) {
auto* networkLabel = new Label(10, 10, 100, 18);
networkLabel->setText("No network");
networkLabel->setVerticalAlignment(Label::Alignement::CENTER);
networkLabel->setHorizontalAlignment(Label::Alignement::CENTER);
networkLabel->setFontSize(18);
launcherWindow->addChild(networkLabel);
}

std::vector<gui::ElementBase*> apps;

int placementIndex = 0;

for (const auto& app : AppManager::appList) {
if (!app->visible) {
// If an app is not visible (AKA. Background app)
// Skip it

continue;
}

auto* box = new Box(60 + 119 * (placementIndex%2), 164 + 95 * (placementIndex / 2), 80, 80);

auto* img = new Image(app->path / "../icon.png", 20, 6, 40, 40);
img->load();
box->addChild(img);

auto* text = new Label(0, 46, 80, 34);
text->setText(app->name);
text->setVerticalAlignment(Label::Alignement::CENTER);
text->setHorizontalAlignment(Label::Alignement::CENTER);
text->setFontSize(16);
box->addChild(text);

if(storage::Path notifs = (app->path / ".." / "unread.txt"); notifs.exists()) {
storage::FileStream file(notifs.str(), storage::READ);

if(file.size() > 0) {
auto* notifBox = new Box(66, 0, 14, 14);
notifBox->setRadius(7);
notifBox->setBackgroundColor(COLOR_WARNING);
box->addChild(notifBox);
}

file.close();
}

launcherWindow->addChild(box);

applicationsIconsMap.insert({
box,
app
});

placementIndex++;
}

// Update variables
allocated = true;
dirty = false;

lastClockUpdate = millis();
lastBatteryUpdate = millis();

// Is this the inverse of "triggerPower()" ?
StandbyMode::restorePower();
}

bool applications::launcher::iconTouched() {
return targetApp != nullptr;
}

std::shared_ptr<AppManager::App> applications::launcher::getApp() {
return targetApp;
}

void applications::launcher::free() {
if (!allocated) {
return;
}

launcherWindow->free();

// TODO : This is not a "free"
launcherWindow = std::make_shared<Window>();

applicationsIconsMap.clear();

clockLabel = nullptr;
dateLabel = nullptr;

allocated = false;
dirty = true;
}

int launcher()
{
if(AppManager::isAnyVisibleApp()) {
Expand Down Expand Up @@ -134,4 +328,4 @@ int launcher()

eventHandlerApp.removeInterval(evid);
return -1;
}
}
15 changes: 15 additions & 0 deletions lib/applications/src/launcher.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,21 @@
// application launcher en une fonction. Lorsqu'une app est choisie, il l'ajoute a la liste des programes a executer et quitte.
// et le thread app l'éxécute immédiatement.

namespace AppManager {
class App;
}

namespace applications::launcher {
void init();
void free();

void update();
void draw();

bool iconTouched();
std::shared_ptr<AppManager::App> getApp();
}

int launcher();

#endif
12 changes: 4 additions & 8 deletions lib/gsm/src/gsm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ namespace GSM
#ifdef ESP_PLATFORM
gsm.println((message + "\r").c_str());

std::cout << "[GSM] Sending request" << std::endl;
std::cout << "[GSM] Sending request: " << message << ", " << answerKey << std::endl;

uint64_t lastChar = millis();
std::string answer = "";
Expand Down Expand Up @@ -576,9 +576,7 @@ namespace GSM
}
}

int getBatteryLevel() {
// That's not "Level" but "Percent"

double getBatteryLevel() {
const float voltage = getVoltage();

if (voltage == -1) {
Expand All @@ -587,11 +585,9 @@ namespace GSM
}

// Thanks NumWorks for the regression app
double batteryLevel = 3.083368 * std::pow(voltage, 3) - 37.21203 * std::pow(voltage, 2) + 150.5735 * voltage - 203.3347;

batteryLevel = std::clamp(batteryLevel, 0.0, 1.0);
const double batteryLevel = 3.083368 * std::pow(voltage, 3) - 37.21203 * std::pow(voltage, 2) + 150.5735 * voltage - 203.3347;

return static_cast<int>(batteryLevel * 100);
return std::clamp(batteryLevel, 0.0, 1.0);

// if (voltage > 4.12)
// return 100;
Expand Down
2 changes: 1 addition & 1 deletion lib/gsm/src/gsm.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ namespace GSM
void acceptCall();
void rejectCall();

int getBatteryLevel();
double getBatteryLevel();
void getHour();

int getNetworkStatus();
Expand Down
5 changes: 5 additions & 0 deletions lib/gui/src/ElementBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <threads.hpp>

#include <iostream>
#include <libsystem.hpp>

// TODO : Remove this, the user need to define its widget for the screen itself.
gui::ElementBase *gui::ElementBase::widgetPressed = nullptr;
Expand Down Expand Up @@ -463,6 +464,10 @@ gui::ElementBase *gui::ElementBase::getParent() const

void gui::ElementBase::addChild(gui::ElementBase *child)
{
if (child == nullptr) {
throw libsystem::exceptions::RuntimeError("Child can't be null.");
}

m_children.push_back(child);
child->m_parent = this;
}
Expand Down
Loading

0 comments on commit 5267594

Please sign in to comment.