Merge develop into main (#348)

## App state

Improved app state management in `LoaderService` and `GuiService`:

- Re-ordered some of the state transitions
- Hardened `GuiService` for repeated events (that might trigger a re-render of an app that's already rendered)
- Validate state transitions in `LoaderService` and crash if an app transitions from the wrong state to the next one.

## LoaderService

- Removed `tt::loader::` functions and expose `LoaderService` interface publicly.
- Implement `stopAll()` and `stopAll(id)` which stops all instances of an app, including any apps that were launched by it.
- Rename `stop()` functions to `stopTop()`
- Created `stopTop(id)` which only stops the top-most app when the app id matches.
- Moved `loader::LoaderEvent` to `loader::LoaderService::Event`
- Changed app instance `std::stack` to `std::vector`

## Improvements

- `ElfApp`: error 22 now shows a hint that `main()` might be missing
- Starting, installing and uninstalling apps now stops any running app (and its children) on the stack

## Bugfixes

- `HttpdReq` out of memory issue now shows an error message and doesn't crash anymore (this would happen on devices without PSRAM with WiFi active, when an app was installed)
- `GuiService::hideApp()` lock should not wait for timeout and now waits indefinitely
- `Buildscript/release-sdk-current.sh` deletes the previous local release before building a new one

## Code correctness

- App classes were made `final`
- Apps that had a `void start()` now have a `LaunchId start()`
- `tt::app::State`: renamed `Started` to `Created` and `Stopped` to `Destroyed` to properly reflect earlier name changes
This commit is contained in:
Ken Van Hoeylandt
2025-09-27 18:04:09 +02:00
committed by GitHub
parent dcf28d0868
commit f6cdabf3c0
48 changed files with 504 additions and 342 deletions
@@ -13,11 +13,11 @@
namespace tt::app {
enum class State {
Initial, // App is being activated in loader
Started, // App is in memory
Showing, // App view is created
Hiding, // App view is destroyed
Stopped // App is not in memory
Initial, // AppInstance was created, but the state hasn't advanced yet
Created, // App was placed into memory
Showing, // App view was created
Hiding, // App view was destroyed
Destroyed // App was removed from memory
};
/**
@@ -1,7 +1,9 @@
#pragma once
#include <Tactility/app/App.h>
namespace tt::app::i2cscanner {
void start();
LaunchId start();
}
@@ -1,7 +1,9 @@
#pragma once
#include <Tactility/app/App.h>
namespace tt::app::launcher {
void start();
LaunchId start();
}
@@ -1,7 +1,9 @@
#pragma once
#include <Tactility/app/App.h>
namespace tt::app::localesettings {
void start();
LaunchId start();
}
@@ -1,7 +1,9 @@
#pragma once
#include <Tactility/app/App.h>
namespace tt::app::timedatesettings {
void start();
LaunchId start();
}
@@ -1,10 +1,11 @@
#pragma once
#include <Tactility/app/App.h>
#include <Tactility/Bundle.h>
namespace tt::app::timezone {
void start();
LaunchId start();
std::string getResultName(const Bundle& bundle);
std::string getResultCode(const Bundle& bundle);
@@ -45,7 +45,7 @@ public:
/**
* Start the app with optional pre-filled fields.
*/
void start(const std::string& ssid = "", const std::string& password = "");
LaunchId start(const std::string& ssid = "", const std::string& password = "");
bool optSsidParameter(const std::shared_ptr<const Bundle>& bundle, std::string& ssid);
@@ -1,7 +1,7 @@
#pragma once
#ifdef ESP_PLATFORM
#include "Tactility/service/Service.h"
#include <Tactility/service/Service.h>
#include <Tactility/Mutex.h>
@@ -17,19 +17,19 @@ namespace tt::service::gui {
#define GUI_THREAD_FLAG_EXIT (1 << 2)
#define GUI_THREAD_FLAG_ALL (GUI_THREAD_FLAG_DRAW | GUI_THREAD_FLAG_INPUT | GUI_THREAD_FLAG_EXIT)
class GuiService : public Service {
class GuiService final : public Service {
// Thread and lock
Thread* thread = nullptr;
Mutex mutex = Mutex(Mutex::Type::Recursive);
PubSub<loader::LoaderEvent>::SubscriptionHandle loader_pubsub_subscription = nullptr;
PubSub<loader::LoaderService::Event>::SubscriptionHandle loader_pubsub_subscription = nullptr;
// Layers and Canvas
lv_obj_t* appRootWidget = nullptr;
lv_obj_t* statusbarWidget = nullptr;
// App-specific
std::shared_ptr<app::AppContext> appToRender = nullptr;
std::shared_ptr<app::AppInstance> appToRender = nullptr;
lv_obj_t* _Nullable keyboard = nullptr;
lv_group_t* keyboardGroup = nullptr;
@@ -38,7 +38,7 @@ class GuiService : public Service {
static int32_t guiMain();
void onLoaderEvent(loader::LoaderEvent event);
void onLoaderEvent(loader::LoaderService::Event event);
lv_obj_t* createAppViews(lv_obj_t* parent);
@@ -52,7 +52,7 @@ class GuiService : public Service {
tt_check(mutex.unlock());
}
void showApp(std::shared_ptr<app::AppContext> app);
void showApp(std::shared_ptr<app::AppInstance> app);
void hideApp();