Refactor app loading and window management (#609)
This commit is contained in:
committed by
GitHub
parent
dc3f6104b8
commit
37c507544b
@@ -1,68 +0,0 @@
|
||||
/**
|
||||
* @brief key-value storage for general purpose.
|
||||
* Maps strings on a fixed set of data types.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace tt {
|
||||
|
||||
/**
|
||||
* A dictionary that maps keys (strings) onto several atomary types.
|
||||
*/
|
||||
class Bundle final {
|
||||
|
||||
typedef uint32_t Hash;
|
||||
|
||||
enum class Type {
|
||||
Bool,
|
||||
Int32,
|
||||
Int64,
|
||||
String,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
Type type;
|
||||
union {
|
||||
bool value_bool;
|
||||
int32_t value_int32;
|
||||
int64_t value_int64;
|
||||
};
|
||||
std::string value_string;
|
||||
} Value;
|
||||
|
||||
std::unordered_map<std::string, Value> entries;
|
||||
|
||||
public:
|
||||
|
||||
Bundle() = default;
|
||||
|
||||
Bundle(const Bundle& bundle) {
|
||||
this->entries = bundle.entries;
|
||||
}
|
||||
|
||||
bool getBool(const std::string& key) const;
|
||||
int32_t getInt32(const std::string& key) const;
|
||||
int64_t getInt64(const std::string& key) const;
|
||||
std::string getString(const std::string& key) const;
|
||||
|
||||
bool hasBool(const std::string& key) const;
|
||||
bool hasInt32(const std::string& key) const;
|
||||
bool hasInt64(const std::string& key) const;
|
||||
bool hasString(const std::string& key) const;
|
||||
|
||||
bool optBool(const std::string& key, bool& out) const;
|
||||
bool optInt32(const std::string& key, int32_t& out) const;
|
||||
bool optInt64(const std::string& key, int64_t& out) const;
|
||||
bool optString(const std::string& key, std::string& out) const;
|
||||
|
||||
void putBool(const std::string& key, bool value);
|
||||
void putInt32(const std::string& key, int32_t value);
|
||||
void putInt64(const std::string& key, int64_t value);
|
||||
void putString(const std::string& key, const std::string& value);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -1,10 +1,12 @@
|
||||
/**
|
||||
* DEPRECATED: Use TactilityKernels' tactility/paths.h
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <tactility/filesystem/file_system.h>
|
||||
|
||||
|
||||
namespace tt {
|
||||
|
||||
bool findFirstMountedSdCardPath(std::string& path);
|
||||
@@ -1,41 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace tt {
|
||||
|
||||
/**
|
||||
* Settings that persist on NVS flash for ESP32.
|
||||
* On simulator, the settings are only in-memory.
|
||||
*
|
||||
* Note that on ESP32, there are limitations:
|
||||
* - namespace name is limited by NVS_NS_NAME_MAX_SIZE (generally 16 characters)
|
||||
* - key is limited by NVS_KEY_NAME_MAX_SIZE (generally 16 characters)
|
||||
*/
|
||||
class Preferences {
|
||||
|
||||
const char* namespace_;
|
||||
|
||||
public:
|
||||
explicit Preferences(const char* namespace_) {
|
||||
this->namespace_ = namespace_;
|
||||
}
|
||||
|
||||
bool hasBool(const std::string& key) const;
|
||||
bool hasInt32(const std::string& key) const;
|
||||
bool hasInt64(const std::string& key) const;
|
||||
bool hasString(const std::string& key) const;
|
||||
|
||||
bool optBool(const std::string& key, bool& out) const;
|
||||
bool optInt32(const std::string& key, int32_t& out) const;
|
||||
bool optInt64(const std::string& key, int64_t& out) const;
|
||||
bool optString(const std::string& key, std::string& out) const;
|
||||
|
||||
void putBool(const std::string& key, bool value);
|
||||
void putInt32(const std::string& key, int32_t value);
|
||||
void putInt64(const std::string& key, int64_t value);
|
||||
void putString(const std::string& key, const std::string& value);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -3,7 +3,6 @@
|
||||
#include <tactility/concurrent/dispatcher.h>
|
||||
#include <tactility/device.h>
|
||||
#include <tactility/module.h>
|
||||
#include <Tactility/app/AppManifest.h>
|
||||
|
||||
#include <functional>
|
||||
|
||||
|
||||
@@ -1,116 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "Tactility/app/AppContext.h"
|
||||
|
||||
#include <Tactility/Bundle.h>
|
||||
#include <Tactility/Mutex.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
// Forward declarations
|
||||
typedef struct _lv_obj_t lv_obj_t;
|
||||
|
||||
namespace tt::app {
|
||||
|
||||
// Forward declarations
|
||||
class AppContext;
|
||||
enum class Result;
|
||||
|
||||
typedef unsigned int LaunchId;
|
||||
|
||||
class App {
|
||||
|
||||
Mutex mutex;
|
||||
|
||||
struct ResultHolder {
|
||||
Result result;
|
||||
std::unique_ptr<Bundle> resultData;
|
||||
|
||||
explicit ResultHolder(Result result) : result(result), resultData(nullptr) {}
|
||||
|
||||
ResultHolder(Result result, std::unique_ptr<Bundle> resultData) :
|
||||
result(result),
|
||||
resultData(std::move(resultData)) {}
|
||||
};
|
||||
|
||||
std::unique_ptr<ResultHolder> resultHolder;
|
||||
|
||||
public:
|
||||
|
||||
App() = default;
|
||||
virtual ~App() = default;
|
||||
|
||||
virtual void onCreate(AppContext& appContext) {}
|
||||
virtual void onDestroy(AppContext& appContext) {}
|
||||
virtual void onShow(AppContext& appContext, lv_obj_t* parent) {}
|
||||
virtual void onHide(AppContext& appContext) {}
|
||||
/** resultData could be null */
|
||||
virtual void onResult(AppContext& appContext, LaunchId launchId, Result result, std::unique_ptr<Bundle> resultData) {}
|
||||
|
||||
Mutex& getMutex() { return mutex; }
|
||||
|
||||
bool hasResult() const { return resultHolder != nullptr; }
|
||||
|
||||
void setResult(Result result, std::unique_ptr<Bundle> resultData = nullptr) {
|
||||
auto lock = getMutex().asScopedLock();
|
||||
lock.lock();
|
||||
resultHolder = std::make_unique<ResultHolder>(result, std::move(resultData));
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by system to extract the result data when this application is finished.
|
||||
* Note that this removes the data from the class!
|
||||
*/
|
||||
bool moveResult(Result& outResult, std::unique_ptr<Bundle>& outBundle) {
|
||||
auto lock = getMutex().asScopedLock();
|
||||
lock.lock();
|
||||
|
||||
if (resultHolder == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
outResult = resultHolder->result;
|
||||
outBundle = std::move(resultHolder->resultData);
|
||||
resultHolder = nullptr;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
std::shared_ptr<App> create() { return std::shared_ptr<T>(new T); }
|
||||
|
||||
/**
|
||||
* @brief Start an app
|
||||
* @param[in] id application name or id
|
||||
* @param[in] parameters optional parameters to pass onto the application. can be nullptr.
|
||||
*/
|
||||
LaunchId start(const std::string& id, std::shared_ptr<const Bundle> parameters = nullptr);
|
||||
|
||||
/** @brief Stop the currently showing app. Show the previous app if any app was still running. */
|
||||
void stop();
|
||||
|
||||
/** @brief Stop a specific app and any apps it might have launched on the stack.
|
||||
* @param[in] id the app id
|
||||
*/
|
||||
void stop(const std::string& id);
|
||||
|
||||
/** @brief Stop all app instances that match with this identifier and also stop the apps they started.
|
||||
* @warning onResult() will only be called for the resulting app that gets shown (if any)
|
||||
* @param[in] id the id of the app to stop
|
||||
*/
|
||||
void stopAll(const std::string& id);
|
||||
|
||||
/** @return true if the app is running somewhere in the app stack (doesn't have to be the top-most app) */
|
||||
bool isRunning(const std::string& id);
|
||||
|
||||
/** @return the currently running app context (it is only ever null before the splash screen is shown) */
|
||||
std::shared_ptr<AppContext> getCurrentAppContext();
|
||||
|
||||
/** @return the currently running app (it is only ever null before the splash screen is shown) */
|
||||
std::shared_ptr<App> getCurrentApp();
|
||||
|
||||
bool install(const std::string& path);
|
||||
|
||||
bool uninstall(const std::string& appId);
|
||||
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <Tactility/Bundle.h>
|
||||
#include <memory>
|
||||
|
||||
namespace tt::app {
|
||||
|
||||
// Forward declarations
|
||||
class App;
|
||||
class AppPaths;
|
||||
struct AppManifest;
|
||||
enum class Result;
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
bool hideStatusbar : 1;
|
||||
};
|
||||
unsigned char flags;
|
||||
} Flags;
|
||||
|
||||
/**
|
||||
* The public representation of an application instance.
|
||||
* @warning Do not store references or pointers to these! You can retrieve them via the service registry.
|
||||
*/
|
||||
class AppContext {
|
||||
|
||||
protected:
|
||||
|
||||
virtual ~AppContext() = default;
|
||||
|
||||
public:
|
||||
|
||||
virtual const AppManifest& getManifest() const = 0;
|
||||
virtual std::shared_ptr<const Bundle> getParameters() const = 0;
|
||||
virtual std::unique_ptr<AppPaths> getPaths() const = 0;
|
||||
|
||||
virtual std::shared_ptr<App> getApp() const = 0;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <Tactility/app/AppRegistration.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace tt::app {
|
||||
|
||||
class App;
|
||||
class AppContext;
|
||||
|
||||
/** Application types */
|
||||
enum class Category {
|
||||
/** Standard apps, provided by the system. */
|
||||
System,
|
||||
/** The apps that are launched/shown by the Settings app. The Settings app itself is of type AppTypeSystem. */
|
||||
Settings,
|
||||
/** User-provided apps. */
|
||||
User
|
||||
};
|
||||
|
||||
/** Result status code for application result callback. */
|
||||
enum class Result {
|
||||
Ok = 0U,
|
||||
Cancelled = 1U,
|
||||
Error = 2U
|
||||
};
|
||||
|
||||
class Location {
|
||||
|
||||
std::string path;
|
||||
Location() = default;
|
||||
explicit Location(const std::string& path) : path(path) {}
|
||||
|
||||
public:
|
||||
|
||||
static Location internal() { return {}; }
|
||||
|
||||
static Location external(const std::string& path) {
|
||||
return Location(path);
|
||||
}
|
||||
|
||||
/** Internal apps are all apps that are part of the firmware release. */
|
||||
bool isInternal() const { return path.empty(); }
|
||||
|
||||
/**
|
||||
* External apps are all apps that are not part of the firmware release.
|
||||
* e.g. an application on the sd card or one that is installed in /data
|
||||
*/
|
||||
bool isExternal() const { return !path.empty(); }
|
||||
const std::string& getPath() const { return path; }
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<App>(*CreateApp)();
|
||||
|
||||
struct AppManifest {
|
||||
|
||||
struct Flags {
|
||||
constexpr static uint32_t None = 0;
|
||||
/** Don't show the statusbar */
|
||||
constexpr static uint32_t HideStatusBar = 1 << 0;
|
||||
/** Hint to other systems to not show this app (e.g. in launcher or settings) */
|
||||
constexpr static uint32_t Hidden = 1 << 1;
|
||||
};
|
||||
|
||||
/** The SDK version that was used to compile this app. (e.g. "0.6.0") */
|
||||
std::string targetSdk = {};
|
||||
|
||||
/** Comma-separated list of platforms, e.g. "esp32,esp32s3" */
|
||||
std::string targetPlatforms = {};
|
||||
|
||||
/** The identifier by which the app is launched by the system and other apps. */
|
||||
std::string appId = {};
|
||||
|
||||
/** The user-readable name of the app. Used in UI. */
|
||||
std::string appName = {};
|
||||
|
||||
/** Optional icon. */
|
||||
std::string appIcon = {};
|
||||
|
||||
/** The version as it is displayed to the user (e.g. "1.2.0") */
|
||||
std::string appVersionName = {};
|
||||
|
||||
/** The technical version (must be incremented with new releases of the app */
|
||||
uint64_t appVersionCode = 0;
|
||||
|
||||
/** App category helps with listing apps in Launcher, app list or settings apps. */
|
||||
Category appCategory = Category::User;
|
||||
|
||||
/** Where the app is located */
|
||||
Location appLocation = Location::internal();
|
||||
|
||||
/** Controls various settings */
|
||||
uint16_t appFlags = Flags::None;
|
||||
|
||||
/** Create the instance of the app */
|
||||
CreateApp createApp = nullptr;
|
||||
};
|
||||
|
||||
struct {
|
||||
bool operator()(const std::shared_ptr<AppManifest>& left, const std::shared_ptr<AppManifest>& right) const { return left->appName < right->appName; }
|
||||
} SortAppManifestByName;
|
||||
|
||||
} // namespace
|
||||
@@ -1,47 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
namespace tt::app {
|
||||
|
||||
// Forward declarations
|
||||
class AppManifest;
|
||||
|
||||
class AppPaths {
|
||||
|
||||
const AppManifest& manifest;
|
||||
|
||||
public:
|
||||
|
||||
explicit AppPaths(const AppManifest& manifest) : manifest(manifest) {}
|
||||
|
||||
/**
|
||||
* The user data directory is intended to survive OS upgrades.
|
||||
* The path will not end with a "/".
|
||||
*/
|
||||
std::string getUserDataPath() const;
|
||||
|
||||
/**
|
||||
* The user data directory is intended to survive OS upgrades.
|
||||
* Configuration data should be stored here.
|
||||
* @param[in] childPath the path without a "/" prefix
|
||||
*/
|
||||
std::string getUserDataPath(const std::string& childPath) const;
|
||||
|
||||
/**
|
||||
* You should not store configuration data here.
|
||||
* The path will not end with a "/".
|
||||
* This is mainly used for core apps (system/boot/settings type).
|
||||
*/
|
||||
std::string getAssetsPath() const;
|
||||
|
||||
/**
|
||||
* You should not store configuration data here.
|
||||
* This is mainly used for core apps (system/boot/settings type).
|
||||
* @param[in] childPath the path without a "/" prefix
|
||||
*/
|
||||
std::string getAssetsPath(const std::string& childPath) const;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "App.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace tt::app {
|
||||
|
||||
struct AppManifest;
|
||||
|
||||
/** Register an application with its manifest */
|
||||
void addAppManifest(const AppManifest& manifest);
|
||||
|
||||
/** Remove an app from the registry */
|
||||
bool removeAppManifest(const std::string& id);
|
||||
|
||||
/** Find an application manifest by its id
|
||||
* @param[in] id the manifest id
|
||||
* @return the application manifest if it was found
|
||||
*/
|
||||
std::shared_ptr<AppManifest> findAppManifestById(const std::string& id);
|
||||
|
||||
/** @return a list of all registered apps. This includes user and system apps. */
|
||||
std::vector<std::shared_ptr<AppManifest>> getAppManifests();
|
||||
|
||||
} // namespace
|
||||
@@ -1,36 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "AppManifest.h"
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
|
||||
namespace tt::app {
|
||||
|
||||
typedef void* (*CreateData)();
|
||||
typedef void (*DestroyData)(void* data);
|
||||
/** data is nullable */
|
||||
typedef void (*OnCreate)(void* appContext, void* data);
|
||||
/** data is nullable */
|
||||
typedef void (*OnDestroy)(void* appContext, void* data);
|
||||
/** data is nullable */
|
||||
typedef void (*OnShow)(void* appContext, void* data, lv_obj_t* parent);
|
||||
/** data is nullable */
|
||||
typedef void (*OnHide)(void* appContext, void* data);
|
||||
/** data is nullable, resultData is nullable. */
|
||||
typedef void (*OnResult)(void* appContext, void* data, LaunchId launchId, Result result, Bundle* resultData);
|
||||
|
||||
/** All fields are nullable */
|
||||
void setElfAppParameters(
|
||||
CreateData createData,
|
||||
DestroyData destroyData,
|
||||
OnCreate onCreate,
|
||||
OnDestroy onDestroy,
|
||||
OnShow onShow,
|
||||
OnHide onHide,
|
||||
OnResult onResult
|
||||
);
|
||||
|
||||
std::shared_ptr<App> createElfApp(const std::shared_ptr<AppManifest>& manifest);
|
||||
|
||||
}
|
||||
#endif // ESP_PLATFORM
|
||||
@@ -1,49 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include <Tactility/Bundle.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <Tactility/app/App.h>
|
||||
|
||||
/**
|
||||
* Start the app by its ID and provide:
|
||||
* - a title
|
||||
* - a text
|
||||
* - 0, 1 or more buttons
|
||||
* Show a dialog with a title, a message and 0, 1 or more buttons.
|
||||
*/
|
||||
namespace tt::app::alertdialog {
|
||||
|
||||
/**
|
||||
* Show a dialog with the provided title, message and 0, 1 or more buttons.
|
||||
* @param[in] title the title to show in the toolbar
|
||||
* @param[in] message the message to display
|
||||
* @param[in] buttonLabels the buttons to show
|
||||
* @return the launch id
|
||||
* Show a dialog with the provided title, message and buttons, as a modal child of
|
||||
* @a callerAppInstanceId (a new-model app - see app/manager.h). The caller receives the
|
||||
* result as an APP_EVENT_RESULT in its own event loop: result is the pressed button's index
|
||||
* (>= 0), or a value not matching any button (currently always 1) if the dialog was dismissed
|
||||
* without a button press. No result_bundle. The caller is responsible for calling
|
||||
* app_manager_stop() on the returned instance id once it has handled the result.
|
||||
* @return the new dialog's app instance id
|
||||
*/
|
||||
LaunchId start(const std::string& title, const std::string& message, const std::vector<std::string>& buttonLabels);
|
||||
/**
|
||||
* Show a dialog with the provided title, message and 0, 1 or more buttons.
|
||||
* @param[in] title the title to show in the toolbar
|
||||
* @param[in] message the message to display
|
||||
* @param[in] buttonLabels the buttons to show
|
||||
* @return the launch id
|
||||
*/
|
||||
LaunchId start(const std::string& title, const std::string& message, const std::vector<const char*>& buttonLabels);
|
||||
uint32_t start(uint32_t callerAppInstanceId, const std::string& title, const std::string& message, const std::vector<std::string>& buttonLabels);
|
||||
|
||||
/**
|
||||
* Show a dialog with the provided title, message and an OK button
|
||||
* @param[in] title the title to show in the toolbar
|
||||
* @param[in] message the message to display
|
||||
* @return the launch id
|
||||
*/
|
||||
LaunchId start(const std::string& title, const std::string& message);
|
||||
|
||||
/**
|
||||
* Get the index of the button that the user selected.
|
||||
*
|
||||
* @return a value greater than 0 when a selection was done, or -1 when the app was closed clicking one of the selection buttons.
|
||||
*/
|
||||
int32_t getResultIndex(const Bundle& bundle);
|
||||
/** @copydoc start(uint32_t, const std::string&, const std::string&, const std::vector<std::string>&)
|
||||
* Shows a single "OK" button. */
|
||||
uint32_t start(uint32_t callerAppInstanceId, const std::string& title, const std::string& message);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <Tactility/app/App.h>
|
||||
#include <cstdint>
|
||||
|
||||
namespace tt::app::btmanage {
|
||||
|
||||
LaunchId start();
|
||||
uint32_t start();
|
||||
|
||||
} // namespace tt::app::btmanage
|
||||
|
||||
@@ -1,28 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <Tactility/app/App.h>
|
||||
#include <Tactility/Bundle.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace tt::app::fileselection {
|
||||
|
||||
/**
|
||||
* Show a file selection dialog that allows the user to select an existing file.
|
||||
* This app returns the absolute file path as a result.
|
||||
* Show a file selection dialog that allows the user to select an existing file, as a modal
|
||||
* child of @a callerAppInstanceId (see app_manager_start_for_result()). Result (0 = Ok,
|
||||
* 1 = Cancelled) is delivered back via APP_EVENT_RESULT once this app's thread exits - call
|
||||
* getLastPath() right after receiving it, on result == 0. The caller must call
|
||||
* app_manager_stop() on the returned instance id once that event arrives, to fully reap this
|
||||
* instance.
|
||||
* @return the new app instance id
|
||||
*/
|
||||
LaunchId startForExistingFile();
|
||||
uint32_t startForExistingFile(uint32_t callerAppInstanceId);
|
||||
|
||||
/**
|
||||
* Show a file selection dialog that allows the user to select a new or existing file.
|
||||
* This app returns the absolute file path as a result.
|
||||
* Same as startForExistingFile(), but also allows picking a path that doesn't exist yet (for
|
||||
* "save as"-style flows).
|
||||
*/
|
||||
LaunchId startForExistingOrNewFile();
|
||||
uint32_t startForExistingOrNewFile(uint32_t callerAppInstanceId);
|
||||
|
||||
/**
|
||||
* @param bundle the result bundle of an app
|
||||
* @return the path from the bundle, or empty string if none is present
|
||||
*/
|
||||
std::string getResultPath(const Bundle& bundle);
|
||||
/** @return the path picked by the last FileSelection dialog that closed with result == Ok. Only
|
||||
* one dialog is expected to be open at a time. */
|
||||
std::string getLastPath();
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <Tactility/app/App.h>
|
||||
#include <string>
|
||||
|
||||
namespace tt::app::imageviewer {
|
||||
|
||||
LaunchId start(const std::string& file);
|
||||
/**
|
||||
* Show a full-screen viewer for a single image file. Fire-and-forget: doesn't report any result
|
||||
* back to the caller.
|
||||
* @param file the path to the image file to display
|
||||
*/
|
||||
void start(const std::string& file);
|
||||
|
||||
}
|
||||
@@ -1,21 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include <Tactility/app/App.h>
|
||||
#include <Tactility/Bundle.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
/**
|
||||
* Start the app by its ID and provide:
|
||||
* - a title
|
||||
* - a text
|
||||
* Show a dialog with a title, a message and a text field.
|
||||
*/
|
||||
namespace tt::app::inputdialog {
|
||||
|
||||
LaunchId start(const std::string& title, const std::string& message, const std::string& prefilled = "");
|
||||
/**
|
||||
* Show a dialog with the provided title, message and prefilled text, as a modal child of
|
||||
* @a callerAppInstanceId (a new-model app - see app/manager.h). The caller receives the result
|
||||
* as an APP_EVENT_RESULT in its own event loop: 0 = OK (call getLastText() for the entered
|
||||
* text), 1 = Cancelled or dismissed without a press. The caller is responsible for calling
|
||||
* app_manager_stop() on the returned instance id once it has handled the result.
|
||||
* @return the new dialog's app instance id
|
||||
*/
|
||||
uint32_t start(uint32_t callerAppInstanceId, const std::string& title, const std::string& message, const std::string& prefilled = "");
|
||||
|
||||
/**
|
||||
* @return the text that was in the field when OK was pressed, or otherwise empty string
|
||||
* @return the text entered the last time any InputDialog instance was closed with OK. Only one
|
||||
* dialog is expected to be open at a time - call this right after receiving its
|
||||
* APP_EVENT_RESULT with result == 0.
|
||||
*/
|
||||
std::string getResult(const Bundle& bundle);
|
||||
std::string getLastText();
|
||||
|
||||
}
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <Tactility/app/App.h>
|
||||
#include <string>
|
||||
|
||||
namespace tt::app::notes {
|
||||
|
||||
/**
|
||||
* Start the notes app with the specified text file.
|
||||
* @param[in] filePath the path to the text file to open
|
||||
* @return the launch id
|
||||
*/
|
||||
LaunchId start(const std::string& filePath);
|
||||
void start(const std::string& filePath);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include <Tactility/app/App.h>
|
||||
#include <Tactility/Bundle.h>
|
||||
#include "app/instance.h"
|
||||
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* Start the app by its ID and provide:
|
||||
* - an optional title
|
||||
* - 2 or more items
|
||||
*
|
||||
* If you provide 0 items, the app will auto-close.
|
||||
* If you provide 1 item, the app will auto-close with result index 0
|
||||
* Show a dialog with a title and a list of selectable items.
|
||||
*/
|
||||
namespace tt::app::selectiondialog {
|
||||
|
||||
LaunchId start(const std::string& title, const std::vector<std::string>& items);
|
||||
|
||||
/**
|
||||
* Get the index of the item that the user selected.
|
||||
*
|
||||
* @return a value greater than 0 when a selection was done, or -1 when the app was closed without selecting an item.
|
||||
* Show a selection dialog with the provided title and items, as a modal child of
|
||||
* @a callerAppInstanceId (a new-model app - see app/manager.h). The caller receives the
|
||||
* result as an APP_EVENT_RESULT in its own event loop: result is the selected item's index
|
||||
* (>= 0), -1 if 0 items were provided (an error - the dialog auto-closes without showing
|
||||
* anything), or a value not matching any item (currently always 1) if the dialog was
|
||||
* dismissed without a selection. No result_bundle. If exactly 1 item is provided, the dialog
|
||||
* auto-closes with result index 0 without showing anything. The caller is responsible for
|
||||
* calling app_manager_stop() on the returned instance id once it has handled the result.
|
||||
* @return the new dialog's app instance id
|
||||
*/
|
||||
int32_t getResultIndex(const Bundle& bundle);
|
||||
AppInstanceId start(AppInstanceId callerAppInstanceId, const std::string& title, const std::vector<std::string>& items);
|
||||
|
||||
}
|
||||
|
||||
@@ -6,11 +6,16 @@
|
||||
|
||||
#if defined(CONFIG_TT_TOUCH_CALIBRATION_SUPPORTED)
|
||||
|
||||
#include <Tactility/app/App.h>
|
||||
#include <cstdint>
|
||||
|
||||
namespace tt::app::touchcalibration {
|
||||
|
||||
LaunchId start();
|
||||
/**
|
||||
* Starts calibration as a modal child of @a callerAppInstanceId. Result (Ok=0/Error=2, no
|
||||
* bundle) is delivered as APP_EVENT_RESULT once the user dismisses the outcome screen.
|
||||
* @return the new app instance id
|
||||
*/
|
||||
uint32_t start(uint32_t callerAppInstanceId);
|
||||
|
||||
} // namespace tt::app::touchcalibration
|
||||
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <Tactility/app/App.h>
|
||||
#include <cstdint>
|
||||
|
||||
namespace tt::app::wifimanage {
|
||||
|
||||
LaunchId start();
|
||||
/**
|
||||
* Starts as a modal child of @a callerAppInstanceId (see app_manager_start_for_result()) - an
|
||||
* APP_EVENT_RESULT is delivered back once the user closes this screen (default Cancelled/no
|
||||
* bundle if never explicitly set - callers that just want a "the wifi step is done" signal, like
|
||||
* Setup, can ignore the actual result value).
|
||||
* @return the new app instance id
|
||||
*/
|
||||
uint32_t start(uint32_t callerAppInstanceId);
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <Tactility/app/AppContext.h>
|
||||
|
||||
#include <lvgl.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace tt::lvgl {
|
||||
|
||||
constexpr auto STATUSBAR_ICON_LIMIT = 8;
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "../app/AppContext.h"
|
||||
|
||||
#include <lvgl/widgets/toolbar.h>
|
||||
|
||||
namespace tt::lvgl {
|
||||
|
||||
/** Create a toolbar widget that shows the app name as title */
|
||||
lv_obj_t* toolbar_create(lv_obj_t* parent, const app::AppContext& app);
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <Tactility/DispatcherThread.h>
|
||||
#include <Tactility/Bundle.h>
|
||||
#include <Tactility/PubSub.h>
|
||||
#include <Tactility/RecursiveMutex.h>
|
||||
#include <Tactility/app/AppInstance.h>
|
||||
#include <Tactility/app/AppManifest.h>
|
||||
#include <Tactility/service/Service.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace tt::service::loader {
|
||||
|
||||
|
||||
class LoaderService final : public Service {
|
||||
|
||||
public:
|
||||
|
||||
enum class Event {
|
||||
ApplicationStarted,
|
||||
ApplicationShowing,
|
||||
ApplicationHiding,
|
||||
ApplicationStopped
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
std::shared_ptr<PubSub<Event>> pubsubExternal = std::make_shared<PubSub<Event>>();
|
||||
RecursiveMutex mutex;
|
||||
std::vector<std::shared_ptr<app::AppInstance>> appStack;
|
||||
app::LaunchId nextLaunchId = 0;
|
||||
|
||||
/** The dispatcher thread needs a callstack large enough to accommodate all the dispatched methods.
|
||||
* This includes full LVGL redraw via Gui::redraw()
|
||||
*/
|
||||
std::unique_ptr<DispatcherThread> dispatcherThread = std::make_unique<DispatcherThread>("loader_dispatcher", 6144); // Files app requires ~5k
|
||||
|
||||
void onStartAppMessage(const std::string& id, app::LaunchId launchId, std::shared_ptr<const Bundle> parameters);
|
||||
|
||||
void onStopTopAppMessage(const std::string& id);
|
||||
|
||||
void onStopAllAppMessage(const std::string& id);
|
||||
|
||||
void transitionAppToState(const std::shared_ptr<app::AppInstance>& app, app::State state);
|
||||
|
||||
int findAppInStack(const std::string& id) const;
|
||||
|
||||
bool onStart(ServiceContext& service) override {
|
||||
dispatcherThread->start();
|
||||
return true;
|
||||
}
|
||||
|
||||
void onStop(ServiceContext& service) override {
|
||||
// Send stop signal to thread and wait for thread to finish
|
||||
mutex.withLock([this] {
|
||||
dispatcherThread->stop();
|
||||
});
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Start an app given an app id and an optional bundle with parameters
|
||||
* @param id the app identifier
|
||||
* @param parameters optional parameter bundle (nullable)
|
||||
* @return the launch id
|
||||
*/
|
||||
app::LaunchId start(const std::string& id, std::shared_ptr<const Bundle> parameters);
|
||||
|
||||
/**
|
||||
* @brief Stops the top-most app (the one that is currently active shown to the user
|
||||
* @warning Avoid calling this directly and use stopTop(id) instead
|
||||
*/
|
||||
void stopTop();
|
||||
|
||||
/**
|
||||
* @brief Stops the top-most app if the id is still matching by the time the stop event arrives.
|
||||
* @param id the id of the app to stop
|
||||
*/
|
||||
void stopTop(const std::string& id);
|
||||
|
||||
/**
|
||||
* @brief Stops all apps with the provided id and any apps that were pushed on top of the stack after the original app was started.
|
||||
* @param id the id of the app to stop
|
||||
*/
|
||||
void stopAll(const std::string& id);
|
||||
|
||||
/** @return the AppContext of the top-most application, or nullptr if no app is running. */
|
||||
std::shared_ptr<app::AppContext> getCurrentAppContext();
|
||||
|
||||
/** @return true if the app is running anywhere in the app stack (the app does not have to be the top-most one for this to return true) */
|
||||
bool isRunning(const std::string& id) const;
|
||||
|
||||
/** @return the PubSub object that is responsible for event publishing */
|
||||
std::shared_ptr<PubSub<Event>> getPubsub() const { return pubsubExternal; }
|
||||
};
|
||||
|
||||
/** return the service or nullptr if it's not running */
|
||||
std::shared_ptr<LoaderService> findLoaderService();
|
||||
|
||||
} // namespace
|
||||
Reference in New Issue
Block a user