Service & app paths improvements
|
Before Width: | Height: | Size: 753 B After Width: | Height: | Size: 753 B |
|
Before Width: | Height: | Size: 528 B After Width: | Height: | Size: 528 B |
|
Before Width: | Height: | Size: 142 B After Width: | Height: | Size: 142 B |
|
Before Width: | Height: | Size: 144 B After Width: | Height: | Size: 144 B |
|
Before Width: | Height: | Size: 149 B After Width: | Height: | Size: 149 B |
|
Before Width: | Height: | Size: 146 B After Width: | Height: | Size: 146 B |
|
Before Width: | Height: | Size: 146 B After Width: | Height: | Size: 146 B |
|
Before Width: | Height: | Size: 149 B After Width: | Height: | Size: 149 B |
|
Before Width: | Height: | Size: 149 B After Width: | Height: | Size: 149 B |
|
Before Width: | Height: | Size: 149 B After Width: | Height: | Size: 149 B |
|
Before Width: | Height: | Size: 149 B After Width: | Height: | Size: 149 B |
|
Before Width: | Height: | Size: 149 B After Width: | Height: | Size: 149 B |
|
Before Width: | Height: | Size: 149 B After Width: | Height: | Size: 149 B |
|
Before Width: | Height: | Size: 193 B After Width: | Height: | Size: 193 B |
|
Before Width: | Height: | Size: 196 B After Width: | Height: | Size: 196 B |
|
Before Width: | Height: | Size: 394 B After Width: | Height: | Size: 394 B |
|
Before Width: | Height: | Size: 407 B After Width: | Height: | Size: 407 B |
|
Before Width: | Height: | Size: 524 B After Width: | Height: | Size: 524 B |
|
Before Width: | Height: | Size: 517 B After Width: | Height: | Size: 517 B |
|
Before Width: | Height: | Size: 534 B After Width: | Height: | Size: 534 B |
@ -17,37 +17,31 @@ public:
|
||||
explicit AppPaths(const AppManifest& manifest) : manifest(manifest) {}
|
||||
|
||||
/**
|
||||
* Returns the directory path for the data location for an app.
|
||||
* The data directory is intended to survive OS upgrades.
|
||||
* The user data directory is intended to survive OS upgrades.
|
||||
* The path will not end with a "/".
|
||||
*/
|
||||
std::string getDataDirectory() const;
|
||||
std::string getUserDataPath() const;
|
||||
|
||||
/**
|
||||
* Returns the full path for an entry inside the data location for an app.
|
||||
* The data directory is intended to survive OS upgrades.
|
||||
* 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 getDataPath(const std::string& childPath) const;
|
||||
std::string getUserDataPath(const std::string& childPath) const;
|
||||
|
||||
/**
|
||||
* Returns the directory path for the system location for an app.
|
||||
* The system directory is not intended to survive OS upgrades.
|
||||
* 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 getSystemDirectory() const;
|
||||
std::string getAssetsDirectory() const;
|
||||
|
||||
/**
|
||||
* Returns the full path for an entry inside the system location for an app.
|
||||
* The data directory is not intended to survive OS upgrades.
|
||||
* 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 getSystemPath(const std::string& childPath) const;
|
||||
std::string getAssetsPath(const std::string& childPath) const;
|
||||
};
|
||||
|
||||
}
|
||||
@ -17,37 +17,29 @@ public:
|
||||
explicit ServicePaths(std::shared_ptr<const ServiceManifest> manifest) : manifest(std::move(manifest)) {}
|
||||
|
||||
/**
|
||||
* Returns the directory path for the data location for a service.
|
||||
* The data directory is intended to survive OS upgrades.
|
||||
* The user data directory is intended to survive OS upgrades.
|
||||
* The path will not end with a "/".
|
||||
*/
|
||||
std::string getDataDirectory() const;
|
||||
std::string getUserDataDirectory() const;
|
||||
|
||||
/**
|
||||
* Returns the full path for an entry inside the data location for a service.
|
||||
* The data directory is intended to survive OS upgrades.
|
||||
* 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 getDataPath(const std::string& childPath) const;
|
||||
std::string getUserDataPath(const std::string& childPath) const;
|
||||
|
||||
/**
|
||||
* Returns the directory path for the system location for a service.
|
||||
* The system directory is not intended to survive OS upgrades.
|
||||
* You should not store configuration data here.
|
||||
* The path will not end with a "/".
|
||||
* This is mainly used for core services.
|
||||
*/
|
||||
std::string getSystemDirectory() const;
|
||||
std::string getAssetsDirectory() const;
|
||||
|
||||
/**
|
||||
* Returns the full path for an entry inside the system location for an app.
|
||||
* The data directory is not intended to survive OS upgrades.
|
||||
* 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 getSystemPath(const std::string& childPath) const;
|
||||
std::string getAssetsPath(const std::string& childPath) const;
|
||||
};
|
||||
|
||||
}
|
||||
@ -2,36 +2,43 @@
|
||||
|
||||
#include <Tactility/app/AppManifest.h>
|
||||
#include <Tactility/MountPoints.h>
|
||||
#include <Tactility/file/File.h>
|
||||
|
||||
#include <format>
|
||||
|
||||
#define LVGL_PATH_PREFIX std::string("A:/")
|
||||
#ifdef ESP_PLATFORM
|
||||
#define PARTITION_PREFIX std::string("/")
|
||||
constexpr auto PARTITION_PREFIX = std::string("/");
|
||||
#else
|
||||
#define PARTITION_PREFIX std::string("")
|
||||
constexpr auto PARTITION_PREFIX = std::string("");
|
||||
#endif
|
||||
|
||||
namespace tt::app {
|
||||
|
||||
std::string AppPaths::getDataDirectory() const {
|
||||
std::string AppPaths::getUserDataPath() const {
|
||||
if (manifest.appLocation.isInternal()) {
|
||||
|
||||
return std::format("{}{}/app/{}", PARTITION_PREFIX, file::DATA_PARTITION_NAME, manifest.appId);
|
||||
} else {
|
||||
return std::format("{}/user/{}", file::getFirstPathSegment(manifest.appLocation.getPath()), manifest.appId);
|
||||
}
|
||||
return PARTITION_PREFIX + file::DATA_PARTITION_NAME + "/app/" + manifest.appId;
|
||||
}
|
||||
|
||||
std::string AppPaths::getDataPath(const std::string& childPath) const {
|
||||
std::string AppPaths::getUserDataPath(const std::string& childPath) const {
|
||||
assert(!childPath.starts_with('/'));
|
||||
return PARTITION_PREFIX + file::DATA_PARTITION_NAME + "/app/" + manifest.appId + '/' + childPath;
|
||||
return getUserDataPath() + '/' + childPath;
|
||||
}
|
||||
|
||||
|
||||
std::string AppPaths::getSystemDirectory() const {
|
||||
return PARTITION_PREFIX + file::SYSTEM_PARTITION_NAME + "/app/" + manifest.appId;
|
||||
std::string AppPaths::getAssetsDirectory() const {
|
||||
if (manifest.appLocation.isInternal()) {
|
||||
return std::format("{}{}/app/{}/assets", PARTITION_PREFIX, file::SYSTEM_PARTITION_NAME, manifest.appId);
|
||||
} else {
|
||||
return std::format("{}/assets", manifest.appLocation.getPath());
|
||||
}
|
||||
}
|
||||
|
||||
std::string AppPaths::getSystemPath(const std::string& childPath) const {
|
||||
std::string AppPaths::getAssetsPath(const std::string& childPath) const {
|
||||
assert(!childPath.starts_with('/'));
|
||||
return PARTITION_PREFIX + file::SYSTEM_PARTITION_NAME + "/app/" + manifest.appId + '/' + childPath;
|
||||
return std::format("{}/{}", getAssetsDirectory(), childPath);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -164,11 +164,11 @@ public:
|
||||
const char* logo;
|
||||
// TODO: Replace with automatic asset buckets like on Android
|
||||
if (getSmallestDimension() < 150) { // e.g. Cardputer
|
||||
logo = hal::usb::isUsbBootMode() ? "assets/logo_usb.png" : "assets/logo_small.png";
|
||||
logo = hal::usb::isUsbBootMode() ? "logo_usb.png" : "logo_small.png";
|
||||
} else {
|
||||
logo = hal::usb::isUsbBootMode() ? "assets/logo_usb.png" : "assets/logo.png";
|
||||
logo = hal::usb::isUsbBootMode() ? "logo_usb.png" : "logo.png";
|
||||
}
|
||||
const auto logo_path = "A:" + paths->getSystemPath(logo);
|
||||
const auto logo_path = "A:" + paths->getAssetsPath(logo);
|
||||
TT_LOG_I(TAG, "%s", logo_path.c_str());
|
||||
lv_image_set_src(image, logo_path.c_str());
|
||||
}
|
||||
|
||||
@ -113,9 +113,9 @@ public:
|
||||
const int32_t margin = is_landscape_display ? std::min<int32_t>(available_width / 16, button_size) : 0;
|
||||
|
||||
const auto paths = app.getPaths();
|
||||
const auto apps_icon_path = "A:" + paths->getSystemPath("assets/icon_apps.png");
|
||||
const auto files_icon_path = "A:" + paths->getSystemPath("assets/icon_files.png");
|
||||
const auto settings_icon_path = "A:" + paths->getSystemPath("assets/icon_settings.png");
|
||||
const auto apps_icon_path = "A:" + paths->getAssetsPath("icon_apps.png");
|
||||
const auto files_icon_path = "A:" + paths->getAssetsPath("icon_files.png");
|
||||
const auto settings_icon_path = "A:" + paths->getAssetsPath("icon_settings.png");
|
||||
|
||||
createAppButton(buttons_wrapper, ui_scale, apps_icon_path.c_str(), "AppList", margin);
|
||||
createAppButton(buttons_wrapper, ui_scale, files_icon_path.c_str(), "Files", margin);
|
||||
|
||||
@ -201,7 +201,7 @@ public:
|
||||
lv_obj_set_style_image_recolor_opa(icon, 255, 0);
|
||||
lv_obj_set_style_image_recolor(icon, lv_theme_get_color_primary(parent), 0);
|
||||
|
||||
std::string icon_path = "A:" + app.getPaths()->getSystemPath("search.png");
|
||||
std::string icon_path = "A:" + app.getPaths()->getAssetsPath("search.png");
|
||||
lv_image_set_src(icon, icon_path.c_str());
|
||||
lv_obj_set_style_image_recolor(icon, lv_theme_get_color_primary(parent), 0);
|
||||
|
||||
|
||||
@ -3,32 +3,33 @@
|
||||
#include <Tactility/service/ServiceManifest.h>
|
||||
#include <Tactility/MountPoints.h>
|
||||
|
||||
#define LVGL_PATH_PREFIX std::string("A:/")
|
||||
#include <cassert>
|
||||
#include <format>
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#define PARTITION_PREFIX std::string("/")
|
||||
constexpr auto PARTITION_PREFIX = std::string("/");
|
||||
#else
|
||||
#define PARTITION_PREFIX std::string("")
|
||||
constexpr auto PARTITION_PREFIX = std::string("");
|
||||
#endif
|
||||
|
||||
namespace tt::service {
|
||||
|
||||
std::string ServicePaths::getDataDirectory() const {
|
||||
return PARTITION_PREFIX + file::DATA_PARTITION_NAME + "/service/" + manifest->id;
|
||||
std::string ServicePaths::getUserDataDirectory() const {
|
||||
return std::format("{}{}/service/{}", PARTITION_PREFIX, file::DATA_PARTITION_NAME, manifest->id);
|
||||
}
|
||||
|
||||
std::string ServicePaths::getDataPath(const std::string& childPath) const {
|
||||
std::string ServicePaths::getUserDataPath(const std::string& childPath) const {
|
||||
assert(!childPath.starts_with('/'));
|
||||
return PARTITION_PREFIX + file::DATA_PARTITION_NAME + "/service/" + manifest->id + '/' + childPath;
|
||||
return std::format("{}/{}", getUserDataDirectory(), childPath);
|
||||
}
|
||||
|
||||
std::string ServicePaths::getSystemDirectory() const {
|
||||
return PARTITION_PREFIX + file::SYSTEM_PARTITION_NAME + "/service/" + manifest->id;
|
||||
std::string ServicePaths::getAssetsDirectory() const {
|
||||
return std::format("{}{}/service/{}/assets", PARTITION_PREFIX, file::SYSTEM_PARTITION_NAME, manifest->id);
|
||||
}
|
||||
|
||||
std::string ServicePaths::getSystemPath(const std::string& childPath) const {
|
||||
std::string ServicePaths::getAssetsPath(const std::string& childPath) const {
|
||||
assert(!childPath.starts_with('/'));
|
||||
return PARTITION_PREFIX + file::SYSTEM_PARTITION_NAME + "/service/" + manifest->id + '/' + childPath;
|
||||
return std::format("{}/{}", getAssetsDirectory(), childPath);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -17,12 +17,12 @@ bool GpsService::getConfigurationFilePath(std::string& output) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!file::findOrCreateDirectory(paths->getDataDirectory(), 0777)) {
|
||||
TT_LOG_E(TAG, "Failed to find or create path %s", paths->getDataDirectory().c_str());
|
||||
if (!file::findOrCreateDirectory(paths->getUserDataDirectory(), 0777)) {
|
||||
TT_LOG_E(TAG, "Failed to find or create path %s", paths->getUserDataDirectory().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
output = paths->getDataPath("config.bin");
|
||||
output = paths->getUserDataPath("config.bin");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -163,7 +163,7 @@ class StatusbarService final : public Service {
|
||||
bool show_icon = (gps_state == gps::State::OnPending) || (gps_state == gps::State::On);
|
||||
if (gps_last_state != show_icon) {
|
||||
if (show_icon) {
|
||||
auto icon_path = "A:" + paths->getSystemPath(STATUSBAR_ICON_GPS);
|
||||
auto icon_path = "A:" + paths->getAssetsPath(STATUSBAR_ICON_GPS);
|
||||
lvgl::statusbar_icon_set_image(gps_icon_id, icon_path);
|
||||
lvgl::statusbar_icon_set_visibility(gps_icon_id, true);
|
||||
} else {
|
||||
@ -179,7 +179,7 @@ class StatusbarService final : public Service {
|
||||
const char* desired_icon = getWifiStatusIcon(radio_state, is_secure);
|
||||
if (wifi_last_icon != desired_icon) {
|
||||
if (desired_icon != nullptr) {
|
||||
auto icon_path = "A:" + paths->getSystemPath(desired_icon);
|
||||
auto icon_path = "A:" + paths->getAssetsPath(desired_icon);
|
||||
lvgl::statusbar_icon_set_image(wifi_icon_id, icon_path);
|
||||
lvgl::statusbar_icon_set_visibility(wifi_icon_id, true);
|
||||
} else {
|
||||
@ -193,7 +193,7 @@ class StatusbarService final : public Service {
|
||||
const char* desired_icon = getPowerStatusIcon();
|
||||
if (power_last_icon != desired_icon) {
|
||||
if (desired_icon != nullptr) {
|
||||
auto icon_path = "A:" + paths->getSystemPath(desired_icon);
|
||||
auto icon_path = "A:" + paths->getAssetsPath(desired_icon);
|
||||
lvgl::statusbar_icon_set_image(power_icon_id, icon_path);
|
||||
lvgl::statusbar_icon_set_visibility(power_icon_id, true);
|
||||
} else {
|
||||
@ -212,7 +212,7 @@ class StatusbarService final : public Service {
|
||||
if (state != hal::sdcard::SdCardDevice::State::Timeout) {
|
||||
auto* desired_icon = getSdCardStatusIcon(state);
|
||||
if (sdcard_last_icon != desired_icon) {
|
||||
auto icon_path = "A:" + paths->getSystemPath(desired_icon);
|
||||
auto icon_path = "A:" + paths->getAssetsPath(desired_icon);
|
||||
lvgl::statusbar_icon_set_image(sdcard_icon_id, icon_path);
|
||||
lvgl::statusbar_icon_set_visibility(sdcard_icon_id, true);
|
||||
sdcard_last_icon = desired_icon;
|
||||
|
||||
@ -1,24 +1,19 @@
|
||||
#include "Tactility/service/wifi/Wifi.h"
|
||||
|
||||
#ifndef ESP_PLATFORM
|
||||
|
||||
#include "Tactility/service/ServiceContext.h"
|
||||
#include <Tactility/service/wifi/Wifi.h>
|
||||
|
||||
#include <Tactility/Check.h>
|
||||
#include <Tactility/Log.h>
|
||||
#include <Tactility/Mutex.h>
|
||||
#include <Tactility/PubSub.h>
|
||||
#include <Tactility/service/Service.h>
|
||||
#include <Tactility/service/ServiceManifest.h>
|
||||
|
||||
namespace tt::service::wifi {
|
||||
|
||||
#define TAG "wifi"
|
||||
#define WIFI_CONNECTED_BIT BIT0
|
||||
#define WIFI_FAIL_BIT BIT1
|
||||
constexpr auto* TAG = "Wifi";
|
||||
|
||||
struct Wifi {
|
||||
Wifi() = default;
|
||||
~Wifi() = default;
|
||||
|
||||
/** @brief Locking mechanism for modifying the Wifi instance */
|
||||
Mutex mutex = Mutex(Mutex::Type::Recursive);
|
||||
/** @brief The public event bus */
|
||||
@ -144,13 +139,13 @@ class WifiService final : public Service {
|
||||
|
||||
public:
|
||||
|
||||
bool onStart(TT_UNUSED ServiceContext& service) final {
|
||||
bool onStart(TT_UNUSED ServiceContext& service) override {
|
||||
tt_check(wifi == nullptr);
|
||||
wifi = new Wifi();
|
||||
return true;
|
||||
}
|
||||
|
||||
void onStop(TT_UNUSED ServiceContext& service) final {
|
||||
void onStop(TT_UNUSED ServiceContext& service) override {
|
||||
tt_check(wifi != nullptr);
|
||||
delete wifi;
|
||||
wifi = nullptr;
|
||||
|
||||
@ -39,7 +39,7 @@ void tt_app_get_data_directory(AppPathsHandle handle, char* buffer, size_t* size
|
||||
assert(size != nullptr);
|
||||
assert(*size > 0);
|
||||
auto paths = HANDLE_AS_APP_CONTEXT(handle)->getPaths();
|
||||
auto data_path = paths->getDataDirectory();
|
||||
auto data_path = paths->getUserDataPath();
|
||||
auto expected_length = data_path.length() + 1;
|
||||
if (*size < expected_length) {
|
||||
TT_LOG_E(TAG, "Path buffer not large enough (%d < %d)", *size, expected_length);
|
||||
|
||||
@ -83,6 +83,8 @@ std::string getChildPath(const std::string& basePath, const std::string& childPa
|
||||
|
||||
std::string getLastPathSegment(const std::string& path);
|
||||
|
||||
std::string getFirstPathSegment(const std::string& path);
|
||||
|
||||
typedef int (*ScandirFilter)(const dirent*);
|
||||
|
||||
typedef bool (*ScandirSort)(const dirent&, const dirent&);
|
||||
|
||||
@ -216,6 +216,19 @@ std::string getLastPathSegment(const std::string& path) {
|
||||
}
|
||||
}
|
||||
|
||||
std::string getFirstPathSegment(const std::string& path) {
|
||||
if (path.empty()) {
|
||||
return path;
|
||||
}
|
||||
auto start_index = path[0] == SEPARATOR ? 1 : 0;
|
||||
auto index = path.find_first_of(SEPARATOR, start_index);
|
||||
if (index != std::string::npos) {
|
||||
return path.substr(0, index);
|
||||
} else {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
bool findOrCreateDirectory(const std::string& path, mode_t mode) {
|
||||
if (path.empty()) {
|
||||
return true;
|
||||
|
||||