mirror of
https://github.com/ByteWelder/Tactility.git
synced 2026-02-19 03:13:14 +00:00
Create boot properties file, update ideas.md, use Notes as default txt file launcher
This commit is contained in:
parent
75be23eca2
commit
0bbf3a93a2
2
Data/data/boot.properties
Normal file
2
Data/data/boot.properties
Normal file
@ -0,0 +1,2 @@
|
||||
launcherAppId=Launcher
|
||||
#autoStartAppId=
|
||||
@ -1,2 +0,0 @@
|
||||
This file exists to test the partition.
|
||||
It can be deleted when the partition contains other files.
|
||||
@ -1,40 +1,49 @@
|
||||
# TODOs
|
||||
|
||||
## Higher Priority
|
||||
|
||||
- Store encrypted WiFi credentials in `/data/app/wifi/x.ap.properties` (fixes problem with long SSIDs)
|
||||
- Move WiFi settings from flash to `/data/apps/wifi/wifi.properties` (just the "start on boot")
|
||||
- Move Development settings from flash to `/data/apps/development/development.properties` (just the "start on boot")
|
||||
- Move Display settings from flash to `/data/apps/display/display.properties` (just the "start on boot")
|
||||
- App data directory should be automatically created (and then we can remove the custom code from Notes.cpp)
|
||||
- When an external app fails to load (e.g. due to mapping error) then show an error dialog.
|
||||
- Revisit TinyUSB mouse idea: the bugs related to cleanup seem to be fixed in the library.
|
||||
- Bug: When a Wi-Fi SSID is too long, then it fails to save the credentials
|
||||
- Add a Keyboard setting app to override the behaviour of soft keyboard hiding (e.g. keyboard hardware is present, but the user wants to use a soft keyboard)
|
||||
- HAL for display touch calibration
|
||||
- Add a Keyboard setting in `keyboard.properties` to override the behaviour of soft keyboard hiding (e.g. keyboard hardware is present, but the user wants to use a soft keyboard)
|
||||
- Expose app::Paths to TactilityC
|
||||
- Call tt::lvgl::isSyncSet after HAL init and show an error (and crash?) when it is not set.
|
||||
- External app loading: Check the version of Tactility and check ESP target hardware to check for compatibility.
|
||||
- Localization of texts (load in boot app from sd?)
|
||||
- App packaging
|
||||
- Create more unit tests for `tactility-core`
|
||||
- Make a URL handler. Use it for handling local files. Match file types with apps.
|
||||
|
||||
## Lower Priority
|
||||
|
||||
- Support hot-plugging SD card
|
||||
- Create more unit tests for `tactility`
|
||||
- Explore LVGL9's FreeRTOS functionality
|
||||
- CrashHandler: use "corrupted" flag
|
||||
- CrashHandler: process other types of crashes (WDT?)
|
||||
- Use GPS time to set/update the current time
|
||||
- All drivers (e.g. display, touch, etc.) should call stop() in their destructor, or at least assert that they should not be running.
|
||||
- Fix bug in T-Deck/etc: esp_lvgl_port settings has a large stack size (~9kB) to fix an issue where the T-Deck would get a stackoverflow. This sometimes happens when WiFi is auto-enabled and you open the app while it is still connecting.
|
||||
- Start using non_null (either via MS GSL, or custom)
|
||||
- `hal/Configuration.h` defines C function types: Use C++ std::function instead
|
||||
- Fix system time to not be 1980 (use build year as a minimum). Consider keeping track of the last known time.
|
||||
- Use std::span or string_view in StringUtils https://youtu.be/FRkJCvHWdwQ?t=2754
|
||||
- Fix bug in T-Deck/etc: esp_lvgl_port settings has a large stack size (~9kB) to fix an issue where the T-Deck would get a stackoverflow. This sometimes happens when WiFi is auto-enabled and you open the app while it is still connecting.
|
||||
- Mutex: Implement give/take from ISR support (works only for non-recursive ones)
|
||||
- Extend unPhone power driver: add charging status, usb connection status, etc.
|
||||
- Expose app::Paths to TactilityC
|
||||
- CrashHandler: use "corrupted" flag
|
||||
- CrashHandler: process other types of crashes (WDT?)
|
||||
- Call tt::lvgl::isSyncSet after HAL init and show an error (and crash?) when it is not set.
|
||||
- Create different partition files for different ESP flash size targets (N4, N8, N16, N32)
|
||||
- T-Deck: Clear screen before turning on blacklight
|
||||
- T-Deck: Use knob for UI selection?
|
||||
- Crash monitoring: Keep track of which system phase the app crashed in (e.g. which app in which state)
|
||||
- App::onResult should pass the app id (or launch request id!) that was started, so we can differentiate between multiple types of apps being launched
|
||||
- Create more unit tests for `tactility-core` and `tactility` (PC-only for now)
|
||||
- Show a warning screen if firmware encryption or secure boot are off when saving WiFi credentials.
|
||||
- Show a warning screen when a user plugs in the SD card on a device that only supports mounting at boot.
|
||||
- Localisation of texts (load in boot app from sd?)
|
||||
- Explore LVGL9's FreeRTOS functionality
|
||||
- External app loading: Check version of Tactility and check ESP target hardware to check for compatibility.
|
||||
- Scanning SD card for external apps and auto-register them (in a temporary register?)
|
||||
- Support hot-plugging SD card
|
||||
- All drivers (e.g. display, touch, etc.) should call stop() in their destructor, or at least assert that they should not be running.
|
||||
- Use GPS time to set/update the current time
|
||||
- Remove flex_flow from app_container in Gui.cpp
|
||||
|
||||
# Nice-to-haves
|
||||
|
||||
- Considering the lack of callstack debugging for external apps: allow for some debugging to be exposed during a device crash. Apps could report their state (e.g. an integer value) which can be stored during app operation and retrieve after crash. The same can be done for various OS apps and states. We can keep an array of these numbers to keep track of the last X states, to get an idea of what's going on.
|
||||
- Give external app a different icon. Allow an external app to update their id, icon, type and name once they are running (and persist that info?). Loader will need to be able to find app by (external) location.
|
||||
- Audio player app
|
||||
- Audio recording app
|
||||
@ -51,6 +60,7 @@
|
||||
|
||||
# App Ideas
|
||||
|
||||
- Revisit TinyUSB mouse idea: the bugs related to cleanup seem to be fixed in the library.
|
||||
- Map widget:
|
||||
https://github.com/portapack-mayhem/mayhem-firmware/blob/b66d8b1aa178d8a9cd06436fea788d5d58cb4c8d/firmware/application/ui/ui_geomap.cpp
|
||||
https://github.com/portapack-mayhem/mayhem-firmware/blob/b66d8b1aa178d8a9cd06436fea788d5d58cb4c8d/firmware/tools/generate_world_map.bin.py
|
||||
@ -67,3 +77,4 @@
|
||||
- Compile unix tools to ELF apps?
|
||||
- Todo list
|
||||
- Calendar
|
||||
- Display touch calibration
|
||||
|
||||
18
Tactility/Include/Tactility/BootProperties.h
Normal file
18
Tactility/Include/Tactility/BootProperties.h
Normal file
@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace tt {
|
||||
|
||||
struct BootProperties {
|
||||
/** App to start automatically after the splash screen. */
|
||||
std::string launcherAppId;
|
||||
/** App to start automatically from the launcher screen. */
|
||||
std::string autoStartAppId;
|
||||
};
|
||||
|
||||
bool loadBootProperties(BootProperties& properties);
|
||||
|
||||
bool saveBootProperties(const BootProperties& properties);
|
||||
|
||||
}
|
||||
@ -19,10 +19,6 @@ struct Configuration {
|
||||
const std::vector<const app::AppManifest*> apps = {};
|
||||
/** List of user services */
|
||||
const std::vector<const service::ServiceManifest*> services = {};
|
||||
/** Optional app to start automatically after the splash screen. */
|
||||
const std::string launcherAppId = app::launcher::manifest.id;
|
||||
/** Optional app to start automatically after the splash screen. */
|
||||
const std::string autoStartAppId = {};
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
7
Tactility/Include/Tactility/app/notes/Notes.h
Normal file
7
Tactility/Include/Tactility/app/notes/Notes.h
Normal file
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
namespace tt::app::notes {
|
||||
|
||||
void start(const std::string& filePath);
|
||||
|
||||
}
|
||||
@ -1,7 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
namespace tt::app::textviewer {
|
||||
|
||||
void start(const std::string& file);
|
||||
|
||||
}
|
||||
36
Tactility/Source/BootProperties.cpp
Normal file
36
Tactility/Source/BootProperties.cpp
Normal file
@ -0,0 +1,36 @@
|
||||
#include "Tactility/BootProperties.h"
|
||||
|
||||
#include <Tactility/LogEsp.h>
|
||||
#include <Tactility/file/PropertiesFile.h>
|
||||
|
||||
namespace tt {
|
||||
|
||||
constexpr auto* TAG = "BootProperties";
|
||||
constexpr auto* PROPERTIES_FILE = "/data/boot.properties";
|
||||
constexpr auto* PROPERTIES_KEY_LAUNCHER_APP_ID = "launcherAppId";
|
||||
constexpr auto* PROPERTIES_KEY_AUTO_START_APP_ID = "autoStartAppId";
|
||||
|
||||
bool loadBootProperties(BootProperties& properties) {
|
||||
if (!file::loadPropertiesFile(PROPERTIES_FILE, [&properties](auto& key, auto& value) {
|
||||
if (key == PROPERTIES_KEY_AUTO_START_APP_ID) {
|
||||
properties.autoStartAppId = value;
|
||||
} else if (key == PROPERTIES_KEY_LAUNCHER_APP_ID) {
|
||||
properties.launcherAppId = value;
|
||||
}
|
||||
})) {
|
||||
TT_LOG_E(TAG, "Failed to load %s", PROPERTIES_FILE);
|
||||
return false;
|
||||
};
|
||||
|
||||
return !properties.launcherAppId.empty();
|
||||
}
|
||||
|
||||
bool saveBootProperties(const BootProperties& bootProperties) {
|
||||
assert(!bootProperties.launcherAppId.empty());
|
||||
std::map<std::string, std::string> properties;
|
||||
properties[PROPERTIES_KEY_AUTO_START_APP_ID] = bootProperties.autoStartAppId;
|
||||
properties[PROPERTIES_KEY_LAUNCHER_APP_ID] = bootProperties.launcherAppId;
|
||||
return file::savePropertiesFile(PROPERTIES_FILE, properties);
|
||||
}
|
||||
|
||||
}
|
||||
@ -54,7 +54,6 @@ namespace app {
|
||||
namespace serialconsole { extern const AppManifest manifest; }
|
||||
namespace settings { extern const AppManifest manifest; }
|
||||
namespace systeminfo { extern const AppManifest manifest; }
|
||||
namespace textviewer { extern const AppManifest manifest; }
|
||||
namespace timedatesettings { extern const AppManifest manifest; }
|
||||
namespace timezone { extern const AppManifest manifest; }
|
||||
namespace usbsettings { extern const AppManifest manifest; }
|
||||
@ -96,7 +95,6 @@ static void registerSystemApps() {
|
||||
addApp(app::settings::manifest);
|
||||
addApp(app::selectiondialog::manifest);
|
||||
addApp(app::systeminfo::manifest);
|
||||
addApp(app::textviewer::manifest);
|
||||
addApp(app::timedatesettings::manifest);
|
||||
addApp(app::timezone::manifest);
|
||||
addApp(app::usbsettings::manifest);
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
#include <Tactility/kernel/SystemEvents.h>
|
||||
|
||||
#include <lvgl.h>
|
||||
#include <Tactility/BootProperties.h>
|
||||
#include <Tactility/CpuAffinity.h>
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
@ -105,9 +106,14 @@ class BootApp : public App {
|
||||
}
|
||||
#endif
|
||||
|
||||
const auto* config = getConfiguration();
|
||||
assert(!config->launcherAppId.empty());
|
||||
service::loader::startApp(config->launcherAppId);
|
||||
BootProperties boot_properties;
|
||||
if (!loadBootProperties(boot_properties) || boot_properties.launcherAppId.empty()) {
|
||||
TT_LOG_E(TAG, "Launcher not configured");
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
|
||||
service::loader::startApp(boot_properties.launcherAppId);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
#include "Tactility/app/alertdialog/AlertDialog.h"
|
||||
#include "Tactility/app/imageviewer/ImageViewer.h"
|
||||
#include "Tactility/app/inputdialog/InputDialog.h"
|
||||
#include "Tactility/app/textviewer/TextViewer.h"
|
||||
#include "Tactility/app/notes/Notes.h"
|
||||
#include "Tactility/app/ElfApp.h"
|
||||
#include "Tactility/lvgl/Toolbar.h"
|
||||
#include "Tactility/lvgl/LvglSync.h"
|
||||
@ -95,10 +95,10 @@ void View::viewFile(const std::string& path, const std::string& filename) {
|
||||
imageviewer::start(processed_filepath);
|
||||
} else if (isSupportedTextFile(filename)) {
|
||||
if (kernel::getPlatform() == kernel::PlatformEsp) {
|
||||
textviewer::start(processed_filepath);
|
||||
notes::start(processed_filepath);
|
||||
} else {
|
||||
// Remove forward slash, because we need a relative path
|
||||
textviewer::start(processed_filepath.substr(1));
|
||||
notes::start(processed_filepath.substr(1));
|
||||
}
|
||||
} else {
|
||||
TT_LOG_W(TAG, "opening files of this type is not supported");
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
#include <Tactility/Tactility.h>
|
||||
|
||||
#include <lvgl.h>
|
||||
#include <Tactility/BootProperties.h>
|
||||
|
||||
#define TAG "launcher"
|
||||
|
||||
@ -54,11 +55,14 @@ static lv_obj_t* createAppButton(lv_obj_t* parent, const char* title, const char
|
||||
class LauncherApp : public App {
|
||||
|
||||
void onCreate(TT_UNUSED AppContext& app) override {
|
||||
auto* config = getConfiguration();
|
||||
if (!config->autoStartAppId.empty()) {
|
||||
TT_LOG_I(TAG, "auto-starting %s", config->autoStartAppId.c_str());
|
||||
service::loader::startApp(config->autoStartAppId);
|
||||
BootProperties boot_properties;
|
||||
if (!loadBootProperties(boot_properties) || boot_properties.autoStartAppId.empty()) {
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
|
||||
TT_LOG_I(TAG, "Starting %s", boot_properties.autoStartAppId.c_str());
|
||||
service::loader::startApp(boot_properties.autoStartAppId);
|
||||
}
|
||||
|
||||
void onShow(TT_UNUSED AppContext& app, lv_obj_t* parent) override {
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
#include <Tactility/app/AppManifest.h>
|
||||
#include <Tactility/file/File.h>
|
||||
#include <Tactility/lvgl/Keyboard.h>
|
||||
#include <Tactility/lvgl/Toolbar.h>
|
||||
#include <Tactility/Assets.h>
|
||||
#include <lvgl.h>
|
||||
@ -8,10 +7,12 @@
|
||||
#include <Tactility/app/fileselection/FileSelection.h>
|
||||
#include <Tactility/hal/sdcard/SdCardDevice.h>
|
||||
#include <Tactility/lvgl/LvglSync.h>
|
||||
#include <Tactility/service/loader/Loader.h>
|
||||
|
||||
namespace tt::app::notes {
|
||||
|
||||
constexpr const char* TAG = "Notes";
|
||||
constexpr auto* TAG = "Notes";
|
||||
constexpr auto* NOTES_FILE_ARGUMENT = "file";
|
||||
|
||||
class NotesApp : public App {
|
||||
|
||||
@ -109,11 +110,20 @@ class NotesApp : public App {
|
||||
|
||||
#pragma endregion Open_Events_Functions
|
||||
|
||||
void onCreate(AppContext& appContext) override {
|
||||
auto parameters = appContext.getParameters();
|
||||
std::string file_path;
|
||||
if (parameters != nullptr && parameters->optString(NOTES_FILE_ARGUMENT, file_path)) {
|
||||
if (!file_path.empty()) {
|
||||
filePath = file_path;
|
||||
}
|
||||
}
|
||||
}
|
||||
void onShow(AppContext& context, lv_obj_t* parent) override {
|
||||
lv_obj_remove_flag(parent, LV_OBJ_FLAG_SCROLLABLE);
|
||||
lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN);
|
||||
|
||||
lv_obj_t* toolbar = tt::lvgl::toolbar_create(parent, context);
|
||||
lv_obj_t* toolbar = lvgl::toolbar_create(parent, context);
|
||||
lv_obj_align(toolbar, LV_ALIGN_TOP_MID, 0, 0);
|
||||
|
||||
uiDropDownMenu = lv_dropdown_create(toolbar);
|
||||
@ -172,6 +182,10 @@ class NotesApp : public App {
|
||||
if (!file::findOrCreateDirectory(context.getPaths()->getDataDirectory(), 0777)) {
|
||||
TT_LOG_E(TAG, "Failed to find or create path %s", context.getPaths()->getDataDirectory().c_str());
|
||||
}
|
||||
|
||||
if (!filePath.empty()) {
|
||||
openFile(filePath);
|
||||
}
|
||||
}
|
||||
|
||||
void onResult(AppContext& appContext, LaunchId launchId, Result result, std::unique_ptr<Bundle> resultData) override {
|
||||
@ -202,4 +216,9 @@ extern const AppManifest manifest = {
|
||||
.createApp = create<NotesApp>
|
||||
};
|
||||
|
||||
void start(const std::string& filePath) {
|
||||
auto parameters = std::make_shared<Bundle>();
|
||||
parameters->putString(NOTES_FILE_ARGUMENT, filePath);
|
||||
service::loader::startApp(manifest.id, parameters);
|
||||
}
|
||||
} // namespace tt::app::notes
|
||||
@ -1,61 +0,0 @@
|
||||
#include "Tactility/lvgl/LabelUtils.h"
|
||||
#include "Tactility/lvgl/Style.h"
|
||||
#include "Tactility/lvgl/Toolbar.h"
|
||||
#include "Tactility/service/loader/Loader.h"
|
||||
|
||||
#include <Tactility/TactilityCore.h>
|
||||
|
||||
#include <lvgl.h>
|
||||
|
||||
#define TAG "text_viewer"
|
||||
#define TEXT_VIEWER_FILE_ARGUMENT "file"
|
||||
|
||||
namespace tt::app::textviewer {
|
||||
|
||||
class TextViewerApp : public App {
|
||||
|
||||
void onShow(AppContext& app, lv_obj_t* parent) override {
|
||||
lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN);
|
||||
lvgl::toolbar_create(parent, app);
|
||||
|
||||
auto* wrapper = lv_obj_create(parent);
|
||||
lv_obj_set_width(wrapper, LV_PCT(100));
|
||||
lv_obj_set_flex_grow(wrapper, 1);
|
||||
lv_obj_set_flex_flow(wrapper, LV_FLEX_FLOW_COLUMN);
|
||||
lv_obj_set_style_pad_all(wrapper, 0, 0);
|
||||
lvgl::obj_set_style_bg_invisible(wrapper);
|
||||
|
||||
auto* label = lv_label_create(wrapper);
|
||||
lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
|
||||
auto parameters = app.getParameters();
|
||||
tt_check(parameters != nullptr, "Parameters missing");
|
||||
bool success = false;
|
||||
std::string file_argument;
|
||||
if (parameters->optString(TEXT_VIEWER_FILE_ARGUMENT, file_argument)) {
|
||||
TT_LOG_I(TAG, "Opening %s", file_argument.c_str());
|
||||
if (lvgl::label_set_text_file(label, file_argument.c_str())) {
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
lv_label_set_text_fmt(label, "Failed to load %s", file_argument.c_str());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
extern const AppManifest manifest = {
|
||||
.id = "TextViewer",
|
||||
.name = "Text Viewer",
|
||||
.type = Type::Hidden,
|
||||
.createApp = create<TextViewerApp>
|
||||
};
|
||||
|
||||
void start(const std::string& file) {
|
||||
auto parameters = std::make_shared<Bundle>();
|
||||
parameters->putString(TEXT_VIEWER_FILE_ARGUMENT, file);
|
||||
service::loader::startApp(manifest.id, parameters);
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
@ -10,4 +10,6 @@ bool loadPropertiesFile(const std::string& filePath, std::map<std::string, std::
|
||||
|
||||
bool loadPropertiesFile(const std::string& filePath, std::function<void(const std::string& key, const std::string& value)> callback);
|
||||
|
||||
bool savePropertiesFile(const std::string& filePath, const std::map<std::string, std::string>& properties);
|
||||
|
||||
}
|
||||
|
||||
@ -53,4 +53,20 @@ bool loadPropertiesFile(const std::string& filePath, std::map<std::string, std::
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
bool savePropertiesFile(const std::string& filePath, const std::map<std::string, std::string>& properties) {
|
||||
FILE* file = fopen(filePath.c_str(), "w");
|
||||
if (file == nullptr) {
|
||||
TT_LOG_E(TAG, "Failed to open %s", filePath.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto& [key, value] : properties) {
|
||||
fprintf(file, "%s=%s\n", key.c_str(), value.c_str());
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user