Refactored events (#621)
Event handling: - Added unified event handling for application, system, and Wi‑Fi events. - Updated all apps to reflect event handling changes Wi-Fi: - Refactored event handling from listener interface to task & event group. - Added direct Wi‑Fi radio controls and improved event subscriptions. - Wi‑Fi screens now refresh asynchronously and handle unavailable devices more gracefully. - Enabled Wi‑Fi by default on in dts files, but radio on/off is still done by code. The main reason was reliable event subscription and consistent devicetree states. - Improved Wi‑Fi shutdown cleanup and radio-state handling. Other: - Renamed the Kernel Display app to Display.
This commit is contained in:
committed by
GitHub
parent
db48dfe812
commit
ab75d2022d
@@ -5,11 +5,13 @@
|
||||
#include <app/event.h>
|
||||
#include <app/manager.h>
|
||||
#include <app/manifest.h>
|
||||
#include <app/scheduler.h>
|
||||
|
||||
#include <lvgl_window_manager/window_manager.h>
|
||||
|
||||
#include <lvgl/icons/shared.h>
|
||||
#include <lvgl/widgets/toolbar.h>
|
||||
#include <tactility/check.h>
|
||||
#include <tactility/drivers/uart_controller.h>
|
||||
#include <tactility/log.h>
|
||||
|
||||
@@ -199,36 +201,42 @@ void createWidgets(lv_obj_t* parent, void* userData) {
|
||||
// endregion
|
||||
}
|
||||
|
||||
int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
int32_t appMain(int argc, char* argv[]) {
|
||||
uint32_t appInstanceId = app_scheduler_current_app_id();
|
||||
Context ctx {};
|
||||
ctx.appInstanceId = appInstanceId;
|
||||
|
||||
TaskEventGroup event_group {};
|
||||
task_event_group_construct(&event_group);
|
||||
|
||||
AppEventSubscription sub {};
|
||||
sub.app_instance_id = appInstanceId;
|
||||
app_event_subscribe(&sub);
|
||||
check(app_event_subscribe(&sub, &event_group) == ERROR_NONE);
|
||||
|
||||
WindowId window = window_manager_create(appInstanceId, createWidgets, &ctx);
|
||||
|
||||
bool shouldClose = false;
|
||||
while (!shouldClose) {
|
||||
task_event_group_wait_any(&event_group, nullptr, portMAX_DELAY);
|
||||
|
||||
AppEvent event {};
|
||||
if (app_event_await(&sub, &event, portMAX_DELAY) != ERROR_NONE) {
|
||||
break;
|
||||
}
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
case APP_EVENT_RESULT:
|
||||
app_manager_stop(event.result.launch_id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
while (app_event_poll(&sub, &event) == ERROR_NONE) {
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
case APP_EVENT_RESULT:
|
||||
app_manager_stop(event.result.launch_id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (shouldClose) break;
|
||||
}
|
||||
}
|
||||
|
||||
window_manager_remove(window);
|
||||
app_event_unsubscribe(&sub);
|
||||
check(app_event_unsubscribe(&sub) == ERROR_NONE);
|
||||
task_event_group_destruct(&event_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3,9 +3,11 @@
|
||||
#include <app/event.h>
|
||||
#include <app/manager.h>
|
||||
#include <app/manifest.h>
|
||||
#include <app/scheduler.h>
|
||||
|
||||
#include <lvgl_window_manager/window_manager.h>
|
||||
|
||||
#include <tactility/check.h>
|
||||
#include <tactility/log.h>
|
||||
|
||||
#include <lvgl.h>
|
||||
@@ -97,29 +99,37 @@ void createWidgets(lv_obj_t* parent, void* userData) {
|
||||
}
|
||||
}
|
||||
|
||||
int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
int32_t appMain(int argc, char* argv[]) {
|
||||
uint32_t appInstanceId = app_scheduler_current_app_id();
|
||||
Context ctx { appInstanceId };
|
||||
ctx.argc = argc;
|
||||
ctx.argv = argv;
|
||||
|
||||
TaskEventGroup event_group {};
|
||||
task_event_group_construct(&event_group);
|
||||
|
||||
AppEventSubscription sub {};
|
||||
sub.app_instance_id = appInstanceId;
|
||||
app_event_subscribe(&sub);
|
||||
check(app_event_subscribe(&sub, &event_group) == ERROR_NONE);
|
||||
|
||||
WindowId window = window_manager_create(appInstanceId, createWidgets, &ctx);
|
||||
|
||||
while (true) {
|
||||
task_event_group_wait_any(&event_group, nullptr, portMAX_DELAY);
|
||||
|
||||
bool shouldClose = false;
|
||||
AppEvent event {};
|
||||
if (app_event_await(&sub, &event, portMAX_DELAY) != ERROR_NONE) {
|
||||
break;
|
||||
}
|
||||
if (event.type == APP_EVENT_CLOSE) {
|
||||
break;
|
||||
while (app_event_poll(&sub, &event) == ERROR_NONE) {
|
||||
if (event.type == APP_EVENT_CLOSE) {
|
||||
shouldClose = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (shouldClose) break;
|
||||
}
|
||||
|
||||
window_manager_remove(window);
|
||||
app_event_unsubscribe(&sub);
|
||||
check(app_event_unsubscribe(&sub) == ERROR_NONE);
|
||||
task_event_group_destruct(&event_group);
|
||||
|
||||
return ctx.result;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <app/manager.h>
|
||||
#include <app/manifest.h>
|
||||
#include <app/install.h>
|
||||
#include <app/scheduler.h>
|
||||
|
||||
#include <format>
|
||||
|
||||
@@ -15,6 +16,7 @@
|
||||
#include <Tactility/file/File.h>
|
||||
#include <Tactility/lvgl/Style.h>
|
||||
|
||||
#include <tactility/check.h>
|
||||
#include <tactility/log.h>
|
||||
|
||||
constexpr auto* TAG = "AppDetails";
|
||||
@@ -104,7 +106,8 @@ void createWidgets(lv_obj_t* parent, void* userData) {
|
||||
}
|
||||
}
|
||||
|
||||
int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
int32_t appMain(int argc, char* argv[]) {
|
||||
uint32_t appInstanceId = app_scheduler_current_app_id();
|
||||
|
||||
Context ctx {};
|
||||
ctx.appInstanceId = appInstanceId;
|
||||
@@ -114,38 +117,43 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
TaskEventGroup event_group {};
|
||||
task_event_group_construct(&event_group);
|
||||
|
||||
AppEventSubscription sub {};
|
||||
sub.app_instance_id = appInstanceId;
|
||||
app_event_subscribe(&sub);
|
||||
check(app_event_subscribe(&sub, &event_group) == ERROR_NONE);
|
||||
|
||||
WindowId window = window_manager_create(appInstanceId, createWidgets, &ctx);
|
||||
|
||||
bool shouldClose = false;
|
||||
while (!shouldClose) {
|
||||
task_event_group_wait_any(&event_group, nullptr, portMAX_DELAY);
|
||||
|
||||
AppEvent event {};
|
||||
if (app_event_await(&sub, &event, portMAX_DELAY) != ERROR_NONE) {
|
||||
break;
|
||||
}
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
case APP_EVENT_RESULT:
|
||||
if (event.result.launch_id == ctx.pendingUninstallDialogId) {
|
||||
if (event.result.result == 0) { // 0 = Yes
|
||||
app_uninstall(ctx.targetManifest.id);
|
||||
shouldClose = true;
|
||||
while (app_event_poll(&sub, &event) == ERROR_NONE) {
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
case APP_EVENT_RESULT:
|
||||
if (event.result.launch_id == ctx.pendingUninstallDialogId) {
|
||||
if (event.result.result == 0) { // 0 = Yes
|
||||
app_uninstall(ctx.targetManifest.id);
|
||||
shouldClose = true;
|
||||
}
|
||||
app_manager_stop(event.result.launch_id);
|
||||
}
|
||||
app_manager_stop(event.result.launch_id);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (shouldClose) break;
|
||||
}
|
||||
}
|
||||
|
||||
window_manager_remove(window);
|
||||
app_event_unsubscribe(&sub);
|
||||
check(app_event_unsubscribe(&sub) == ERROR_NONE);
|
||||
task_event_group_destruct(&event_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -10,9 +10,11 @@
|
||||
#include <app/event.h>
|
||||
#include <app/manager.h>
|
||||
#include <app/manifest.h>
|
||||
#include <app/scheduler.h>
|
||||
|
||||
#include <lvgl_window_manager/window_manager.h>
|
||||
|
||||
#include <tactility/check.h>
|
||||
#include <tactility/log.h>
|
||||
|
||||
#include <lvgl/lvgl.h>
|
||||
@@ -49,7 +51,7 @@ void refresh(Context* ctx);
|
||||
|
||||
void onBackPressed(lv_event_t* event) {
|
||||
auto* ctx = static_cast<Context*>(lv_event_get_user_data(event));
|
||||
AppEvent closeEvent { .type = APP_EVENT_CLOSE, .timestamp = 0, .result = {} };
|
||||
AppEvent closeEvent {.type = APP_EVENT_CLOSE, .timestamp = 0, .result = {}};
|
||||
app_event_emit(ctx->appInstanceId, &closeEvent);
|
||||
}
|
||||
|
||||
@@ -197,33 +199,39 @@ void destroyWidgets(void* userData) {
|
||||
ctx->refreshButton = nullptr;
|
||||
}
|
||||
|
||||
int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
int32_t appMain(int argc, char* argv[]) {
|
||||
uint32_t appInstanceId = app_scheduler_current_app_id();
|
||||
Context ctx;
|
||||
ctx.appInstanceId = appInstanceId;
|
||||
|
||||
TaskEventGroup event_group {};
|
||||
task_event_group_construct(&event_group);
|
||||
|
||||
AppEventSubscription sub {};
|
||||
sub.app_instance_id = appInstanceId;
|
||||
app_event_subscribe(&sub);
|
||||
check(app_event_subscribe(&sub, &event_group) == ERROR_NONE);
|
||||
|
||||
WindowId window = window_manager_create_ext(appInstanceId, createWidgets, destroyWidgets, &ctx);
|
||||
|
||||
bool shouldClose = false;
|
||||
while (!shouldClose) {
|
||||
task_event_group_wait_any(&event_group, nullptr, portMAX_DELAY);
|
||||
|
||||
AppEvent event {};
|
||||
if (app_event_await(&sub, &event, portMAX_DELAY) != ERROR_NONE) {
|
||||
break;
|
||||
}
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
while (app_event_poll(&sub, &event) == ERROR_NONE) {
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (shouldClose) break;
|
||||
}
|
||||
}
|
||||
|
||||
window_manager_remove(window);
|
||||
app_event_unsubscribe(&sub);
|
||||
check(app_event_unsubscribe(&sub) == ERROR_NONE);
|
||||
task_event_group_destruct(&event_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -234,7 +242,7 @@ extern const ::AppManifest manifest = {
|
||||
.id = "tactility.apphub",
|
||||
.name = "App Hub",
|
||||
.category = APP_CATEGORY_SYSTEM,
|
||||
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) }
|
||||
.location = {APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain)}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
} // namespace tt::app::apphub
|
||||
|
||||
@@ -11,12 +11,14 @@
|
||||
#include <app/metadata.h>
|
||||
#include <app/manager.h>
|
||||
#include <app/manifest.h>
|
||||
#include <app/scheduler.h>
|
||||
|
||||
#include <lvgl_window_manager/window_manager.h>
|
||||
|
||||
#include <lvgl/lvgl.h>
|
||||
#include <lvgl/widgets/toolbar.h>
|
||||
|
||||
#include <tactility/check.h>
|
||||
#include <tactility/log.h>
|
||||
|
||||
#include <atomic>
|
||||
@@ -211,7 +213,8 @@ void createWidgets(lv_obj_t* parent, void* userData) {
|
||||
updateViews(ctx);
|
||||
}
|
||||
|
||||
int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
int32_t appMain(int argc, char* argv[]) {
|
||||
uint32_t appInstanceId = app_scheduler_current_app_id();
|
||||
// argv layout: [0]=appId, [1]=appVersionName, [2]=appVersionCode, [3]=appName,
|
||||
// [4]=appDescription, [5]=targetSdk, [6]=file, [7..argc)=targetPlatforms.
|
||||
|
||||
@@ -230,41 +233,46 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
}
|
||||
}
|
||||
|
||||
TaskEventGroup event_group {};
|
||||
task_event_group_construct(&event_group);
|
||||
|
||||
AppEventSubscription sub {};
|
||||
sub.app_instance_id = appInstanceId;
|
||||
app_event_subscribe(&sub);
|
||||
check(app_event_subscribe(&sub, &event_group) == ERROR_NONE);
|
||||
|
||||
WindowId window = window_manager_create(appInstanceId, createWidgets, &ctx);
|
||||
|
||||
bool shouldClose = false;
|
||||
while (!shouldClose) {
|
||||
task_event_group_wait_any(&event_group, nullptr, portMAX_DELAY);
|
||||
|
||||
AppEvent event {};
|
||||
if (app_event_await(&sub, &event, portMAX_DELAY) != ERROR_NONE) {
|
||||
break;
|
||||
}
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
case APP_EVENT_RESULT: {
|
||||
bool confirmed = event.result.result == CONFIRMATION_BUTTON_INDEX;
|
||||
if (event.result.launch_id == ctx.installDialogId && confirmed) {
|
||||
installApp(&ctx);
|
||||
} else if (event.result.launch_id == ctx.uninstallDialogId && confirmed) {
|
||||
uninstallApp(&ctx);
|
||||
} else if (event.result.launch_id == ctx.updateDialogId && confirmed) {
|
||||
updateApp(&ctx);
|
||||
while (app_event_poll(&sub, &event) == ERROR_NONE) {
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
case APP_EVENT_RESULT: {
|
||||
bool confirmed = event.result.result == CONFIRMATION_BUTTON_INDEX;
|
||||
if (event.result.launch_id == ctx.installDialogId && confirmed) {
|
||||
installApp(&ctx);
|
||||
} else if (event.result.launch_id == ctx.uninstallDialogId && confirmed) {
|
||||
uninstallApp(&ctx);
|
||||
} else if (event.result.launch_id == ctx.updateDialogId && confirmed) {
|
||||
updateApp(&ctx);
|
||||
}
|
||||
app_manager_stop(event.result.launch_id);
|
||||
break;
|
||||
}
|
||||
app_manager_stop(event.result.launch_id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
if (shouldClose) break;
|
||||
}
|
||||
}
|
||||
|
||||
window_manager_remove(window);
|
||||
app_event_unsubscribe(&sub);
|
||||
check(app_event_unsubscribe(&sub) == ERROR_NONE);
|
||||
task_event_group_destruct(&event_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
#include <app/event.h>
|
||||
#include <app/manager.h>
|
||||
#include <app/manifest.h>
|
||||
#include <app/scheduler.h>
|
||||
|
||||
#include <lvgl_window_manager/window_manager.h>
|
||||
|
||||
#include <tactility/check.h>
|
||||
|
||||
#include <lvgl.h>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
@@ -78,27 +81,35 @@ void createWidgets(lv_obj_t* parent, void*) {
|
||||
}
|
||||
}
|
||||
|
||||
int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
int32_t appMain(int argc, char* argv[]) {
|
||||
uint32_t appInstanceId = app_scheduler_current_app_id();
|
||||
appListInstanceId = appInstanceId;
|
||||
|
||||
TaskEventGroup event_group {};
|
||||
task_event_group_construct(&event_group);
|
||||
|
||||
AppEventSubscription sub {};
|
||||
sub.app_instance_id = appInstanceId;
|
||||
app_event_subscribe(&sub);
|
||||
check(app_event_subscribe(&sub, &event_group) == ERROR_NONE);
|
||||
|
||||
WindowId window = window_manager_create(appInstanceId, createWidgets, nullptr);
|
||||
|
||||
while (true) {
|
||||
task_event_group_wait_any(&event_group, nullptr, portMAX_DELAY);
|
||||
|
||||
bool shouldClose = false;
|
||||
AppEvent event {};
|
||||
if (app_event_await(&sub, &event, portMAX_DELAY) != ERROR_NONE) {
|
||||
break;
|
||||
}
|
||||
if (event.type == APP_EVENT_CLOSE) {
|
||||
break;
|
||||
while (app_event_poll(&sub, &event) == ERROR_NONE) {
|
||||
if (event.type == APP_EVENT_CLOSE) {
|
||||
shouldClose = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (shouldClose) break;
|
||||
}
|
||||
|
||||
window_manager_remove(window);
|
||||
app_event_unsubscribe(&sub);
|
||||
check(app_event_unsubscribe(&sub) == ERROR_NONE);
|
||||
task_event_group_destruct(&event_group);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,9 +6,12 @@
|
||||
#include <app/event.h>
|
||||
#include <app/manager.h>
|
||||
#include <app/manifest.h>
|
||||
#include <app/scheduler.h>
|
||||
|
||||
#include <lvgl_window_manager/window_manager.h>
|
||||
|
||||
#include <tactility/check.h>
|
||||
|
||||
#include <lvgl/widgets/toolbar.h>
|
||||
#include <lvgl.h>
|
||||
#include <algorithm>
|
||||
@@ -87,32 +90,38 @@ void createWidgets(lv_obj_t* parent, void*) {
|
||||
}
|
||||
}
|
||||
|
||||
int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
int32_t appMain(int argc, char* argv[]) {
|
||||
uint32_t appInstanceId = app_scheduler_current_app_id();
|
||||
appSettingsInstanceId = appInstanceId;
|
||||
|
||||
TaskEventGroup event_group {};
|
||||
task_event_group_construct(&event_group);
|
||||
|
||||
AppEventSubscription sub {};
|
||||
sub.app_instance_id = appInstanceId;
|
||||
app_event_subscribe(&sub);
|
||||
check(app_event_subscribe(&sub, &event_group) == ERROR_NONE);
|
||||
|
||||
WindowId window = window_manager_create(appInstanceId, createWidgets, nullptr);
|
||||
|
||||
bool shouldClose = false;
|
||||
while (!shouldClose) {
|
||||
task_event_group_wait_any(&event_group, nullptr, portMAX_DELAY);
|
||||
|
||||
AppEvent event {};
|
||||
if (app_event_await(&sub, &event, portMAX_DELAY) != ERROR_NONE) {
|
||||
break;
|
||||
}
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
while (app_event_poll(&sub, &event) == ERROR_NONE) {
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (shouldClose) break;
|
||||
}
|
||||
}
|
||||
|
||||
window_manager_remove(window);
|
||||
app_event_unsubscribe(&sub);
|
||||
check(app_event_unsubscribe(&sub) == ERROR_NONE);
|
||||
task_event_group_destruct(&event_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -7,11 +7,13 @@
|
||||
#include <app/event.h>
|
||||
#include <app/manager.h>
|
||||
#include <app/manifest.h>
|
||||
#include <app/scheduler.h>
|
||||
|
||||
#include <lvgl_window_manager/window_manager.h>
|
||||
|
||||
#include <lvgl.h>
|
||||
#include <lvgl/widgets/toolbar.h>
|
||||
#include <tactility/check.h>
|
||||
#include <tactility/log.h>
|
||||
|
||||
namespace tt::app::apwebserver {
|
||||
@@ -121,29 +123,34 @@ void createWidgets(lv_obj_t* parent, void* userData) {
|
||||
ctx->webServerEnabledChanged = true;
|
||||
}
|
||||
|
||||
int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
int32_t appMain(int argc, char* argv[]) {
|
||||
uint32_t appInstanceId = app_scheduler_current_app_id();
|
||||
Context ctx {};
|
||||
ctx.appInstanceId = appInstanceId;
|
||||
ctx.wsSettings = settings::webserver::loadOrGetDefault();
|
||||
|
||||
TaskEventGroup event_group {};
|
||||
task_event_group_construct(&event_group);
|
||||
|
||||
AppEventSubscription sub {};
|
||||
sub.app_instance_id = appInstanceId;
|
||||
app_event_subscribe(&sub);
|
||||
check(app_event_subscribe(&sub, &event_group) == ERROR_NONE);
|
||||
|
||||
WindowId window = window_manager_create(appInstanceId, createWidgets, &ctx);
|
||||
|
||||
bool shouldClose = false;
|
||||
while (!shouldClose) {
|
||||
task_event_group_wait_any(&event_group, nullptr, portMAX_DELAY);
|
||||
|
||||
AppEvent event {};
|
||||
if (app_event_await(&sub, &event, portMAX_DELAY) != ERROR_NONE) {
|
||||
break;
|
||||
}
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
while (app_event_poll(&sub, &event) == ERROR_NONE) {
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (shouldClose) break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,7 +174,8 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
});
|
||||
|
||||
window_manager_remove(window);
|
||||
app_event_unsubscribe(&sub);
|
||||
check(app_event_unsubscribe(&sub) == ERROR_NONE);
|
||||
task_event_group_destruct(&event_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -5,9 +5,12 @@
|
||||
#include <app/event.h>
|
||||
#include <app/manager.h>
|
||||
#include <app/manifest.h>
|
||||
#include <app/scheduler.h>
|
||||
|
||||
#include <lvgl_window_manager/window_manager.h>
|
||||
|
||||
#include <tactility/check.h>
|
||||
|
||||
#include <lvgl/lvgl.h>
|
||||
#include <lvgl/widgets/sliderbox.h>
|
||||
#include <lvgl/widgets/toolbar.h>
|
||||
@@ -211,28 +214,33 @@ void createWidgets(lv_obj_t* parent, void* userData) {
|
||||
});
|
||||
}
|
||||
|
||||
int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
int32_t appMain(int argc, char* argv[]) {
|
||||
uint32_t appInstanceId = app_scheduler_current_app_id();
|
||||
Context ctx {};
|
||||
ctx.appInstanceId = appInstanceId;
|
||||
|
||||
TaskEventGroup event_group {};
|
||||
task_event_group_construct(&event_group);
|
||||
|
||||
AppEventSubscription sub {};
|
||||
sub.app_instance_id = appInstanceId;
|
||||
app_event_subscribe(&sub);
|
||||
check(app_event_subscribe(&sub, &event_group) == ERROR_NONE);
|
||||
|
||||
WindowId window = window_manager_create(appInstanceId, createWidgets, &ctx);
|
||||
|
||||
bool shouldClose = false;
|
||||
while (!shouldClose) {
|
||||
task_event_group_wait_any(&event_group, nullptr, portMAX_DELAY);
|
||||
|
||||
AppEvent event {};
|
||||
if (app_event_await(&sub, &event, portMAX_DELAY) != ERROR_NONE) {
|
||||
break;
|
||||
}
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
while (app_event_poll(&sub, &event) == ERROR_NONE) {
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (shouldClose) break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -242,7 +250,8 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
}
|
||||
|
||||
window_manager_remove(window);
|
||||
app_event_unsubscribe(&sub);
|
||||
check(app_event_unsubscribe(&sub) == ERROR_NONE);
|
||||
task_event_group_destruct(&event_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "tactility/system_event.h"
|
||||
|
||||
#include <tactility/check.h>
|
||||
#include <tactility/delay.h>
|
||||
#include <tactility/drivers/backlight.h>
|
||||
#include <tactility/drivers/display.h>
|
||||
@@ -9,6 +10,7 @@
|
||||
#include <app/event.h>
|
||||
#include <app/manager.h>
|
||||
#include <app/manifest.h>
|
||||
#include <app/scheduler.h>
|
||||
|
||||
#include <lvgl_window_manager/window_manager.h>
|
||||
|
||||
@@ -284,7 +286,8 @@ void runBootSequence(TickType_t startTime) {
|
||||
system_event_emit(KERNEL_EVENT_BOOT_COMPLETED, nullptr, 0);
|
||||
}
|
||||
|
||||
int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
int32_t appMain(int argc, char* argv[]) {
|
||||
uint32_t appInstanceId = app_scheduler_current_app_id();
|
||||
bootAppInstanceId = appInstanceId;
|
||||
const auto start_time = get_ticks();
|
||||
|
||||
@@ -292,9 +295,11 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
isUsbBootSplash = hal::usb::isUsbBootMode();
|
||||
sdCardMissing = false;
|
||||
|
||||
TaskEventGroup event_group {};
|
||||
task_event_group_construct(&event_group);
|
||||
|
||||
AppEventSubscription sub {};
|
||||
sub.app_instance_id = appInstanceId;
|
||||
app_event_subscribe(&sub);
|
||||
check(app_event_subscribe(&sub, &event_group) == ERROR_NONE);
|
||||
|
||||
bootWindowId = window_manager_create(appInstanceId, createSplashWidgets, nullptr);
|
||||
|
||||
@@ -304,19 +309,24 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
// startNextApp() above is what triggers that, via app-module's "save the previously active
|
||||
// app" policy, unless sdCardMissing halted before it.
|
||||
while (true) {
|
||||
task_event_group_wait_any(&event_group, nullptr, portMAX_DELAY);
|
||||
|
||||
bool shouldClose = false;
|
||||
AppEvent event {};
|
||||
if (app_event_await(&sub, &event, portMAX_DELAY) != ERROR_NONE) {
|
||||
break;
|
||||
}
|
||||
if (event.type == APP_EVENT_CLOSE) {
|
||||
break;
|
||||
while (app_event_poll(&sub, &event) == ERROR_NONE) {
|
||||
if (event.type == APP_EVENT_CLOSE) {
|
||||
shouldClose = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (shouldClose) break;
|
||||
}
|
||||
|
||||
if (bootWindowId != 0) {
|
||||
window_manager_remove(bootWindowId);
|
||||
}
|
||||
app_event_unsubscribe(&sub);
|
||||
check(app_event_unsubscribe(&sub) == ERROR_NONE);
|
||||
task_event_group_destruct(&event_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -8,9 +8,11 @@
|
||||
#include <app/event.h>
|
||||
#include <app/manager.h>
|
||||
#include <app/manifest.h>
|
||||
#include <app/scheduler.h>
|
||||
|
||||
#include <lvgl_window_manager/window_manager.h>
|
||||
|
||||
#include <tactility/check.h>
|
||||
#include <tactility/log.h>
|
||||
|
||||
namespace tt::app::btmanage {
|
||||
@@ -199,7 +201,8 @@ void createWidgets(lv_obj_t* parent, void* userData) {
|
||||
ctx->unlock();
|
||||
}
|
||||
|
||||
int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
int32_t appMain(int argc, char* argv[]) {
|
||||
uint32_t appInstanceId = app_scheduler_current_app_id();
|
||||
Context ctx;
|
||||
ctx.appInstanceId = appInstanceId;
|
||||
ctx.bindings = (Bindings) {
|
||||
@@ -220,9 +223,11 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
ctx.state.updateScanResults();
|
||||
ctx.state.updatePairedPeers();
|
||||
|
||||
TaskEventGroup event_group {};
|
||||
task_event_group_construct(&event_group);
|
||||
|
||||
AppEventSubscription sub {};
|
||||
sub.app_instance_id = appInstanceId;
|
||||
app_event_subscribe(&sub);
|
||||
check(app_event_subscribe(&sub, &event_group) == ERROR_NONE);
|
||||
|
||||
WindowId window = window_manager_create(appInstanceId, createWidgets, &ctx);
|
||||
|
||||
@@ -243,16 +248,18 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
|
||||
bool shouldClose = false;
|
||||
while (!shouldClose) {
|
||||
task_event_group_wait_any(&event_group, nullptr, portMAX_DELAY);
|
||||
|
||||
AppEvent event {};
|
||||
if (app_event_await(&sub, &event, portMAX_DELAY) != ERROR_NONE) {
|
||||
break;
|
||||
}
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
while (app_event_poll(&sub, &event) == ERROR_NONE) {
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (shouldClose) break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,7 +277,8 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
}
|
||||
|
||||
window_manager_remove(window);
|
||||
app_event_unsubscribe(&sub);
|
||||
check(app_event_unsubscribe(&sub) == ERROR_NONE);
|
||||
task_event_group_destruct(&event_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -11,9 +11,11 @@
|
||||
#include <app/event.h>
|
||||
#include <app/manager.h>
|
||||
#include <app/manifest.h>
|
||||
#include <app/scheduler.h>
|
||||
|
||||
#include <lvgl_window_manager/window_manager.h>
|
||||
|
||||
#include <tactility/check.h>
|
||||
#include <tactility/device.h>
|
||||
#include <tactility/drivers/bluetooth.h>
|
||||
#include <tactility/log.h>
|
||||
@@ -178,7 +180,8 @@ void createWidgets(lv_obj_t* parent, void* userData) {
|
||||
updateViews(ctx);
|
||||
}
|
||||
|
||||
int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
int32_t appMain(int argc, char* argv[]) {
|
||||
uint32_t appInstanceId = app_scheduler_current_app_id();
|
||||
|
||||
Context ctx {};
|
||||
ctx.appInstanceId = appInstanceId;
|
||||
@@ -199,38 +202,42 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
device_put(btDevice);
|
||||
}
|
||||
|
||||
TaskEventGroup event_group {};
|
||||
task_event_group_construct(&event_group);
|
||||
|
||||
AppEventSubscription sub {};
|
||||
sub.app_instance_id = appInstanceId;
|
||||
app_event_subscribe(&sub);
|
||||
check(app_event_subscribe(&sub, &event_group) == ERROR_NONE);
|
||||
|
||||
WindowId window = window_manager_create(appInstanceId, createWidgets, &ctx);
|
||||
|
||||
bool shouldClose = false;
|
||||
while (!shouldClose) {
|
||||
task_event_group_wait_any(&event_group, nullptr, portMAX_DELAY);
|
||||
|
||||
AppEvent event {};
|
||||
if (app_event_await(&sub, &event, portMAX_DELAY) != ERROR_NONE) {
|
||||
break;
|
||||
}
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
case APP_EVENT_RESULT:
|
||||
if (event.result.result == 0) { // 0 = Yes
|
||||
if (isCurrentlyConnected(&ctx)) {
|
||||
if (ctx.profileId == BT_PROFILE_HID_HOST) {
|
||||
bluetooth::hidHostDisconnect();
|
||||
} else {
|
||||
bluetooth::disconnect(ctx.addr, ctx.profileId);
|
||||
}
|
||||
}
|
||||
bluetooth::unpair(ctx.addr);
|
||||
while (app_event_poll(&sub, &event) == ERROR_NONE) {
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
}
|
||||
app_manager_stop(event.result.launch_id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
break;
|
||||
case APP_EVENT_RESULT:
|
||||
if (event.result.result == 0) { // 0 = Yes
|
||||
if (isCurrentlyConnected(&ctx)) {
|
||||
if (ctx.profileId == BT_PROFILE_HID_HOST) {
|
||||
bluetooth::hidHostDisconnect();
|
||||
} else {
|
||||
bluetooth::disconnect(ctx.addr, ctx.profileId);
|
||||
}
|
||||
}
|
||||
bluetooth::unpair(ctx.addr);
|
||||
shouldClose = true;
|
||||
}
|
||||
app_manager_stop(event.result.launch_id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (shouldClose) break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,7 +247,8 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
}
|
||||
|
||||
window_manager_remove(window);
|
||||
app_event_unsubscribe(&sub);
|
||||
check(app_event_unsubscribe(&sub) == ERROR_NONE);
|
||||
task_event_group_destruct(&event_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -10,9 +10,11 @@
|
||||
#include <app/event.h>
|
||||
#include <app/manager.h>
|
||||
#include <app/manifest.h>
|
||||
#include <app/scheduler.h>
|
||||
|
||||
#include <lvgl_window_manager/window_manager.h>
|
||||
|
||||
#include <tactility/check.h>
|
||||
#include <tactility/log.h>
|
||||
|
||||
#include <lvgl/lvgl.h>
|
||||
@@ -167,7 +169,8 @@ void switchChannel(Context* ctx, const std::string& chatChannel) {
|
||||
|
||||
namespace {
|
||||
|
||||
int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
int32_t appMain(int argc, char* argv[]) {
|
||||
uint32_t appInstanceId = app_scheduler_current_app_id();
|
||||
Context ctx {};
|
||||
ctx.appInstanceId = appInstanceId;
|
||||
ctx.isFirstLaunch = !settingsFileExists();
|
||||
@@ -178,40 +181,44 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
}
|
||||
enableEspNow(&ctx);
|
||||
|
||||
ctx.receiveSubscription = service::espnow::subscribeReceiver(
|
||||
TaskEventGroup event_group {};
|
||||
task_event_group_construct(&event_group);
|
||||
|
||||
AppEventSubscription sub {};
|
||||
check(app_event_subscribe(&sub, &event_group) == ERROR_NONE);
|
||||
|
||||
WindowId window = window_manager_create(appInstanceId, createWidgets, &ctx);
|
||||
|
||||
auto espnow_subscription = service::espnow::subscribeReceiver(
|
||||
[&ctx](const esp_now_recv_info_t* receiveInfo, const uint8_t* data, int length) {
|
||||
onReceive(&ctx, receiveInfo, data, length);
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
AppEventSubscription sub {};
|
||||
sub.app_instance_id = appInstanceId;
|
||||
app_event_subscribe(&sub);
|
||||
|
||||
WindowId window = window_manager_create(appInstanceId, createWidgets, &ctx);
|
||||
|
||||
bool shouldClose = false;
|
||||
while (!shouldClose) {
|
||||
task_event_group_wait_any(&event_group, nullptr, portMAX_DELAY);
|
||||
|
||||
AppEvent event {};
|
||||
if (app_event_await(&sub, &event, portMAX_DELAY) != ERROR_NONE) {
|
||||
break;
|
||||
}
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
while (app_event_poll(&sub, &event) == ERROR_NONE) {
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (shouldClose) break;
|
||||
}
|
||||
}
|
||||
|
||||
window_manager_remove(window);
|
||||
app_event_unsubscribe(&sub);
|
||||
|
||||
service::espnow::unsubscribeReceiver(ctx.receiveSubscription);
|
||||
service::espnow::unsubscribeReceiver(espnow_subscription);
|
||||
disableEspNow(&ctx);
|
||||
|
||||
window_manager_remove(window);
|
||||
check(app_event_unsubscribe(&sub) == ERROR_NONE);
|
||||
task_event_group_destruct(&event_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,11 +8,13 @@
|
||||
#include <app/event.h>
|
||||
#include <app/manager.h>
|
||||
#include <app/manifest.h>
|
||||
#include <app/scheduler.h>
|
||||
|
||||
#include <lvgl_window_manager/window_manager.h>
|
||||
|
||||
#include <lvgl.h>
|
||||
#include <qrcode.h>
|
||||
#include <tactility/check.h>
|
||||
#include <tactility/drivers/pointer.h>
|
||||
#include <tactility/log.h>
|
||||
|
||||
@@ -149,35 +151,41 @@ void createWidgets(lv_obj_t* parent, void* userData) {
|
||||
}
|
||||
}
|
||||
|
||||
int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
int32_t appMain(int argc, char* argv[]) {
|
||||
uint32_t appInstanceId = app_scheduler_current_app_id();
|
||||
Context ctx {};
|
||||
ctx.appInstanceId = appInstanceId;
|
||||
|
||||
TaskEventGroup event_group {};
|
||||
task_event_group_construct(&event_group);
|
||||
|
||||
AppEventSubscription sub {};
|
||||
sub.app_instance_id = appInstanceId;
|
||||
app_event_subscribe(&sub);
|
||||
check(app_event_subscribe(&sub, &event_group) == ERROR_NONE);
|
||||
|
||||
WindowId window = window_manager_create(appInstanceId, createWidgets, &ctx);
|
||||
|
||||
if (!ctx.hasFatalError) {
|
||||
bool shouldClose = false;
|
||||
while (!shouldClose) {
|
||||
task_event_group_wait_any(&event_group, nullptr, portMAX_DELAY);
|
||||
|
||||
AppEvent event {};
|
||||
if (app_event_await(&sub, &event, portMAX_DELAY) != ERROR_NONE) {
|
||||
break;
|
||||
}
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
while (app_event_poll(&sub, &event) == ERROR_NONE) {
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (shouldClose) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
window_manager_remove(window);
|
||||
app_event_unsubscribe(&sub);
|
||||
check(app_event_unsubscribe(&sub) == ERROR_NONE);
|
||||
task_event_group_destruct(&event_group);
|
||||
|
||||
bool continuePressed = ctx.continuePressed;
|
||||
|
||||
|
||||
@@ -10,9 +10,11 @@
|
||||
#include <app/event.h>
|
||||
#include <app/manager.h>
|
||||
#include <app/manifest.h>
|
||||
#include <app/scheduler.h>
|
||||
|
||||
#include <lvgl_window_manager/window_manager.h>
|
||||
|
||||
#include <tactility/check.h>
|
||||
#include <tactility/log.h>
|
||||
|
||||
#include <lvgl.h>
|
||||
@@ -162,7 +164,8 @@ void createWidgets(lv_obj_t* parent, void* userData) {
|
||||
updateViewState(ctx);
|
||||
}
|
||||
|
||||
int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
int32_t appMain(int argc, char* argv[]) {
|
||||
uint32_t appInstanceId = app_scheduler_current_app_id();
|
||||
Context ctx {};
|
||||
ctx.appInstanceId = appInstanceId;
|
||||
ctx.service = service::development::findService();
|
||||
@@ -174,9 +177,11 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
TaskEventGroup event_group {};
|
||||
task_event_group_construct(&event_group);
|
||||
|
||||
AppEventSubscription sub {};
|
||||
sub.app_instance_id = appInstanceId;
|
||||
app_event_subscribe(&sub);
|
||||
check(app_event_subscribe(&sub, &event_group) == ERROR_NONE);
|
||||
|
||||
WindowId window = window_manager_create(appInstanceId, createWidgets, &ctx);
|
||||
|
||||
@@ -197,16 +202,18 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
|
||||
bool shouldClose = false;
|
||||
while (!shouldClose) {
|
||||
task_event_group_wait_any(&event_group, nullptr, portMAX_DELAY);
|
||||
|
||||
AppEvent event {};
|
||||
if (app_event_await(&sub, &event, portMAX_DELAY) != ERROR_NONE) {
|
||||
break;
|
||||
}
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
while (app_event_poll(&sub, &event) == ERROR_NONE) {
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (shouldClose) break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,7 +223,8 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
lvgl_unlock();
|
||||
|
||||
window_manager_remove(window);
|
||||
app_event_unsubscribe(&sub);
|
||||
check(app_event_unsubscribe(&sub) == ERROR_NONE);
|
||||
task_event_group_destruct(&event_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+25
-18
@@ -1,4 +1,5 @@
|
||||
#include <lvgl/lvgl.h>
|
||||
#include <tactility/check.h>
|
||||
#include <tactility/device.h>
|
||||
#include <tactility/drivers/backlight.h>
|
||||
#include <tactility/drivers/display.h>
|
||||
@@ -12,8 +13,8 @@
|
||||
#include <Tactility/settings/DisplaySettings.h>
|
||||
|
||||
#include <app/event.h>
|
||||
#include <app/manager.h>
|
||||
#include <app/manifest.h>
|
||||
#include <app/scheduler.h>
|
||||
|
||||
#include <lvgl_window_manager/window_manager.h>
|
||||
|
||||
@@ -25,11 +26,11 @@
|
||||
#include <sdkconfig.h>
|
||||
#endif
|
||||
|
||||
namespace tt::app::kerneldisplay {
|
||||
namespace tt::app::display {
|
||||
|
||||
extern const ::AppManifest manifest;
|
||||
|
||||
constexpr auto* TAG = "KernelDisplay";
|
||||
constexpr auto* TAG = "Display";
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -304,34 +305,40 @@ void persistIfUpdated(Context& ctx) {
|
||||
}
|
||||
}
|
||||
|
||||
int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
int32_t appMain(int argc, char* argv[]) {
|
||||
uint32_t appInstanceId = app_scheduler_current_app_id();
|
||||
Context ctx {};
|
||||
ctx.appInstanceId = appInstanceId;
|
||||
|
||||
TaskEventGroup event_group {};
|
||||
task_event_group_construct(&event_group);
|
||||
|
||||
AppEventSubscription sub {};
|
||||
sub.app_instance_id = appInstanceId;
|
||||
app_event_subscribe(&sub);
|
||||
check(app_event_subscribe(&sub, &event_group) == ERROR_NONE);
|
||||
|
||||
WindowId window = window_manager_create(appInstanceId, createWidgets, &ctx);
|
||||
|
||||
bool shouldClose = false;
|
||||
while (!shouldClose) {
|
||||
task_event_group_wait_any(&event_group, nullptr, portMAX_DELAY);
|
||||
|
||||
AppEvent event {};
|
||||
if (app_event_await(&sub, &event, portMAX_DELAY) != ERROR_NONE) {
|
||||
break;
|
||||
}
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
persistIfUpdated(ctx);
|
||||
shouldClose = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
while (app_event_poll(&sub, &event) == ERROR_NONE) {
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
persistIfUpdated(ctx);
|
||||
shouldClose = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (shouldClose) break;
|
||||
}
|
||||
}
|
||||
|
||||
window_manager_remove(window);
|
||||
app_event_unsubscribe(&sub);
|
||||
check(app_event_unsubscribe(&sub) == ERROR_NONE);
|
||||
task_event_group_destruct(&event_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -345,4 +352,4 @@ extern const ::AppManifest manifest = {
|
||||
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) }
|
||||
};
|
||||
|
||||
} // namespace tt::app::kerneldisplay
|
||||
} // namespace tt::app::display
|
||||
@@ -4,9 +4,12 @@
|
||||
#include <app/event.h>
|
||||
#include <app/manager.h>
|
||||
#include <app/manifest.h>
|
||||
#include <app/scheduler.h>
|
||||
|
||||
#include <lvgl_window_manager/window_manager.h>
|
||||
|
||||
#include <tactility/check.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace tt::app::files {
|
||||
@@ -25,39 +28,45 @@ void createWidgets(lv_obj_t* parent, void* userData) {
|
||||
ctx->view->init(ctx->appInstanceId, parent);
|
||||
}
|
||||
|
||||
int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
int32_t appMain(int argc, char* argv[]) {
|
||||
uint32_t appInstanceId = app_scheduler_current_app_id();
|
||||
auto state = std::make_shared<State>();
|
||||
View view(state);
|
||||
CreateContext createContext { &view, appInstanceId };
|
||||
|
||||
TaskEventGroup event_group {};
|
||||
task_event_group_construct(&event_group);
|
||||
|
||||
AppEventSubscription sub {};
|
||||
sub.app_instance_id = appInstanceId;
|
||||
app_event_subscribe(&sub);
|
||||
check(app_event_subscribe(&sub, &event_group) == ERROR_NONE);
|
||||
|
||||
WindowId window = window_manager_create(appInstanceId, createWidgets, &createContext);
|
||||
|
||||
bool shouldClose = false;
|
||||
while (!shouldClose) {
|
||||
task_event_group_wait_any(&event_group, nullptr, portMAX_DELAY);
|
||||
|
||||
AppEvent event {};
|
||||
if (app_event_await(&sub, &event, portMAX_DELAY) != ERROR_NONE) {
|
||||
break;
|
||||
}
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
case APP_EVENT_RESULT:
|
||||
view.onResult(event.result.launch_id, event.result.result);
|
||||
app_manager_stop(event.result.launch_id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
while (app_event_poll(&sub, &event) == ERROR_NONE) {
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
case APP_EVENT_RESULT:
|
||||
view.onResult(event.result.launch_id, event.result.result);
|
||||
app_manager_stop(event.result.launch_id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (shouldClose) break;
|
||||
}
|
||||
}
|
||||
|
||||
view.deinit();
|
||||
window_manager_remove(window);
|
||||
app_event_unsubscribe(&sub);
|
||||
check(app_event_unsubscribe(&sub) == ERROR_NONE);
|
||||
task_event_group_destruct(&event_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -5,9 +5,12 @@
|
||||
#include <app/event.h>
|
||||
#include <app/manager.h>
|
||||
#include <app/manifest.h>
|
||||
#include <app/scheduler.h>
|
||||
|
||||
#include <lvgl_window_manager/window_manager.h>
|
||||
|
||||
#include <tactility/check.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
@@ -43,7 +46,8 @@ void createWidgets(lv_obj_t* parent, void* userData) {
|
||||
ctx->view->init(parent, ctx->mode);
|
||||
}
|
||||
|
||||
int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
int32_t appMain(int argc, char* argv[]) {
|
||||
uint32_t appInstanceId = app_scheduler_current_app_id();
|
||||
// argv layout: [0]="existing" or "existing_or_new".
|
||||
|
||||
Context ctx {};
|
||||
@@ -62,24 +66,31 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
app_event_emit(appInstanceId, &closeEvent);
|
||||
});
|
||||
|
||||
TaskEventGroup event_group {};
|
||||
task_event_group_construct(&event_group);
|
||||
|
||||
AppEventSubscription sub {};
|
||||
sub.app_instance_id = appInstanceId;
|
||||
app_event_subscribe(&sub);
|
||||
check(app_event_subscribe(&sub, &event_group) == ERROR_NONE);
|
||||
|
||||
WindowId window = window_manager_create(appInstanceId, createWidgets, &ctx);
|
||||
|
||||
while (true) {
|
||||
task_event_group_wait_any(&event_group, nullptr, portMAX_DELAY);
|
||||
|
||||
bool shouldClose = false;
|
||||
AppEvent event {};
|
||||
if (app_event_await(&sub, &event, portMAX_DELAY) != ERROR_NONE) {
|
||||
break;
|
||||
}
|
||||
if (event.type == APP_EVENT_CLOSE) {
|
||||
break;
|
||||
while (app_event_poll(&sub, &event) == ERROR_NONE) {
|
||||
if (event.type == APP_EVENT_CLOSE) {
|
||||
shouldClose = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (shouldClose) break;
|
||||
}
|
||||
|
||||
window_manager_remove(window);
|
||||
app_event_unsubscribe(&sub);
|
||||
check(app_event_unsubscribe(&sub) == ERROR_NONE);
|
||||
task_event_group_destruct(&event_group);
|
||||
|
||||
return ctx.result;
|
||||
}
|
||||
|
||||
@@ -9,9 +9,11 @@
|
||||
#include <app/event.h>
|
||||
#include <app/manager.h>
|
||||
#include <app/manifest.h>
|
||||
#include <app/scheduler.h>
|
||||
|
||||
#include <lvgl_window_manager/window_manager.h>
|
||||
|
||||
#include <tactility/check.h>
|
||||
#include <tactility/device.h>
|
||||
#include <tactility/time.h>
|
||||
|
||||
@@ -257,7 +259,8 @@ void createWidgets(lv_obj_t* parent, void* userData) {
|
||||
updateDeviceStates(ctx);
|
||||
}
|
||||
|
||||
int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
int32_t appMain(int argc, char* argv[]) {
|
||||
uint32_t appInstanceId = app_scheduler_current_app_id();
|
||||
Context ctx {};
|
||||
ctx.appInstanceId = appInstanceId;
|
||||
|
||||
@@ -267,51 +270,56 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
updateDeviceStates(&ctx);
|
||||
});
|
||||
|
||||
TaskEventGroup event_group {};
|
||||
task_event_group_construct(&event_group);
|
||||
|
||||
AppEventSubscription sub {};
|
||||
sub.app_instance_id = appInstanceId;
|
||||
app_event_subscribe(&sub);
|
||||
check(app_event_subscribe(&sub, &event_group) == ERROR_NONE);
|
||||
|
||||
WindowId window = window_manager_create(appInstanceId, createWidgets, &ctx);
|
||||
ctx.timer->start();
|
||||
|
||||
bool shouldClose = false;
|
||||
while (!shouldClose) {
|
||||
task_event_group_wait_any(&event_group, nullptr, portMAX_DELAY);
|
||||
|
||||
AppEvent event {};
|
||||
if (app_event_await(&sub, &event, portMAX_DELAY) != ERROR_NONE) {
|
||||
break;
|
||||
}
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
case APP_EVENT_RESULT:
|
||||
if (ctx.hasPendingDelete) {
|
||||
ctx.hasPendingDelete = false;
|
||||
if (event.result.result == 0) { // 0 = Yes
|
||||
lvgl_lock();
|
||||
std::erase_if(ctx.deviceRows, [&ctx](const DeviceRow& row) {
|
||||
return row.device == ctx.pendingDeleteDevice;
|
||||
});
|
||||
lvgl_unlock();
|
||||
while (app_event_poll(&sub, &event) == ERROR_NONE) {
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
case APP_EVENT_RESULT:
|
||||
if (ctx.hasPendingDelete) {
|
||||
ctx.hasPendingDelete = false;
|
||||
if (event.result.result == 0) { // 0 = Yes
|
||||
lvgl_lock();
|
||||
std::erase_if(ctx.deviceRows, [&ctx](const DeviceRow& row) {
|
||||
return row.device == ctx.pendingDeleteDevice;
|
||||
});
|
||||
lvgl_unlock();
|
||||
|
||||
gps_settings_remove_configuration_at(ctx.pendingDeleteIndex);
|
||||
ctx.pendingDeleteDevice = nullptr;
|
||||
gps_settings_remove_configuration_at(ctx.pendingDeleteIndex);
|
||||
ctx.pendingDeleteDevice = nullptr;
|
||||
|
||||
lvgl_lock();
|
||||
rebuildDeviceList(&ctx);
|
||||
lvgl_unlock();
|
||||
lvgl_lock();
|
||||
rebuildDeviceList(&ctx);
|
||||
lvgl_unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
app_manager_stop(event.result.launch_id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
app_manager_stop(event.result.launch_id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (shouldClose) break;
|
||||
}
|
||||
}
|
||||
|
||||
ctx.timer->stop();
|
||||
window_manager_remove(window);
|
||||
app_event_unsubscribe(&sub);
|
||||
check(app_event_unsubscribe(&sub) == ERROR_NONE);
|
||||
task_event_group_destruct(&event_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2,12 +2,14 @@
|
||||
|
||||
#include <lvgl.h>
|
||||
|
||||
#include <tactility/check.h>
|
||||
#include <tactility/device.h>
|
||||
#include <tactility/drivers/grove.h>
|
||||
|
||||
#include <app/event.h>
|
||||
#include <app/manager.h>
|
||||
#include <app/manifest.h>
|
||||
#include <app/scheduler.h>
|
||||
|
||||
#include <lvgl_window_manager/window_manager.h>
|
||||
|
||||
@@ -89,33 +91,39 @@ void createWidgets(lv_obj_t* parent, void* userData) {
|
||||
}
|
||||
}
|
||||
|
||||
int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
int32_t appMain(int argc, char* argv[]) {
|
||||
uint32_t appInstanceId = app_scheduler_current_app_id();
|
||||
Context ctx {};
|
||||
ctx.appInstanceId = appInstanceId;
|
||||
|
||||
TaskEventGroup event_group {};
|
||||
task_event_group_construct(&event_group);
|
||||
|
||||
AppEventSubscription sub {};
|
||||
sub.app_instance_id = appInstanceId;
|
||||
app_event_subscribe(&sub);
|
||||
check(app_event_subscribe(&sub, &event_group) == ERROR_NONE);
|
||||
|
||||
WindowId window = window_manager_create(appInstanceId, createWidgets, &ctx);
|
||||
|
||||
bool shouldClose = false;
|
||||
while (!shouldClose) {
|
||||
task_event_group_wait_any(&event_group, nullptr, portMAX_DELAY);
|
||||
|
||||
AppEvent event {};
|
||||
if (app_event_await(&sub, &event, portMAX_DELAY) != ERROR_NONE) {
|
||||
break;
|
||||
}
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
while (app_event_poll(&sub, &event) == ERROR_NONE) {
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (shouldClose) break;
|
||||
}
|
||||
}
|
||||
|
||||
window_manager_remove(window);
|
||||
app_event_unsubscribe(&sub);
|
||||
check(app_event_unsubscribe(&sub) == ERROR_NONE);
|
||||
task_event_group_destruct(&event_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -9,9 +9,11 @@
|
||||
#include <app/manager.h>
|
||||
#include <app/manifest.h>
|
||||
#include <app/paths.h>
|
||||
#include <app/scheduler.h>
|
||||
|
||||
#include <lvgl_window_manager/window_manager.h>
|
||||
|
||||
#include <tactility/check.h>
|
||||
#include <tactility/drivers/i2c_controller.h>
|
||||
#include <tactility/log.h>
|
||||
#include <tactility/preferences.h>
|
||||
@@ -384,34 +386,40 @@ void stopScanningIfRunning(Context* ctx) {
|
||||
}
|
||||
}
|
||||
|
||||
int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
int32_t appMain(int argc, char* argv[]) {
|
||||
uint32_t appInstanceId = app_scheduler_current_app_id();
|
||||
Context ctx;
|
||||
ctx.appInstanceId = appInstanceId;
|
||||
|
||||
TaskEventGroup event_group {};
|
||||
task_event_group_construct(&event_group);
|
||||
|
||||
AppEventSubscription sub {};
|
||||
sub.app_instance_id = appInstanceId;
|
||||
app_event_subscribe(&sub);
|
||||
check(app_event_subscribe(&sub, &event_group) == ERROR_NONE);
|
||||
|
||||
WindowId window = window_manager_create(appInstanceId, createWidgets, &ctx);
|
||||
|
||||
bool shouldClose = false;
|
||||
while (!shouldClose) {
|
||||
task_event_group_wait_any(&event_group, nullptr, portMAX_DELAY);
|
||||
|
||||
AppEvent event {};
|
||||
if (app_event_await(&sub, &event, portMAX_DELAY) != ERROR_NONE) {
|
||||
break;
|
||||
}
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
stopScanningIfRunning(&ctx);
|
||||
shouldClose = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
while (app_event_poll(&sub, &event) == ERROR_NONE) {
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
stopScanningIfRunning(&ctx);
|
||||
shouldClose = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (shouldClose) break;
|
||||
}
|
||||
}
|
||||
|
||||
window_manager_remove(window);
|
||||
app_event_unsubscribe(&sub);
|
||||
check(app_event_unsubscribe(&sub) == ERROR_NONE);
|
||||
task_event_group_destruct(&event_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <app/event.h>
|
||||
#include <app/manager.h>
|
||||
#include <app/manifest.h>
|
||||
#include <app/scheduler.h>
|
||||
|
||||
#include <lvgl_window_manager/window_manager.h>
|
||||
|
||||
@@ -82,36 +83,42 @@ void createWidgets(lv_obj_t* parent, void* userData) {
|
||||
}
|
||||
}
|
||||
|
||||
int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
int32_t appMain(int argc, char* argv[]) {
|
||||
uint32_t appInstanceId = app_scheduler_current_app_id();
|
||||
check(argc > 0, "Parameters not set");
|
||||
|
||||
Context ctx {};
|
||||
ctx.appInstanceId = appInstanceId;
|
||||
ctx.filePath = argv[0];
|
||||
|
||||
TaskEventGroup event_group {};
|
||||
task_event_group_construct(&event_group);
|
||||
|
||||
AppEventSubscription sub {};
|
||||
sub.app_instance_id = appInstanceId;
|
||||
app_event_subscribe(&sub);
|
||||
check(app_event_subscribe(&sub, &event_group) == ERROR_NONE);
|
||||
|
||||
WindowId window = window_manager_create(appInstanceId, createWidgets, &ctx);
|
||||
|
||||
bool shouldClose = false;
|
||||
while (!shouldClose) {
|
||||
task_event_group_wait_any(&event_group, nullptr, portMAX_DELAY);
|
||||
|
||||
AppEvent event {};
|
||||
if (app_event_await(&sub, &event, portMAX_DELAY) != ERROR_NONE) {
|
||||
break;
|
||||
}
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
while (app_event_poll(&sub, &event) == ERROR_NONE) {
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (shouldClose) break;
|
||||
}
|
||||
}
|
||||
|
||||
window_manager_remove(window);
|
||||
app_event_unsubscribe(&sub);
|
||||
check(app_event_unsubscribe(&sub) == ERROR_NONE);
|
||||
task_event_group_destruct(&event_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3,10 +3,12 @@
|
||||
#include <app/event.h>
|
||||
#include <app/manager.h>
|
||||
#include <app/manifest.h>
|
||||
#include <app/scheduler.h>
|
||||
|
||||
#include <lvgl_window_manager/window_manager.h>
|
||||
|
||||
#include <lvgl/widgets/toolbar.h>
|
||||
#include <tactility/check.h>
|
||||
#include <tactility/log.h>
|
||||
|
||||
#include <lvgl.h>
|
||||
@@ -106,29 +108,37 @@ void createWidgets(lv_obj_t* parent, void* userData) {
|
||||
createButton(ctx, button_wrapper, "Cancel", nullptr);
|
||||
}
|
||||
|
||||
int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
int32_t appMain(int argc, char* argv[]) {
|
||||
uint32_t appInstanceId = app_scheduler_current_app_id();
|
||||
Context ctx { appInstanceId };
|
||||
ctx.argc = argc;
|
||||
ctx.argv = argv;
|
||||
|
||||
TaskEventGroup event_group {};
|
||||
task_event_group_construct(&event_group);
|
||||
|
||||
AppEventSubscription sub {};
|
||||
sub.app_instance_id = appInstanceId;
|
||||
app_event_subscribe(&sub);
|
||||
check(app_event_subscribe(&sub, &event_group) == ERROR_NONE);
|
||||
|
||||
WindowId window = window_manager_create(appInstanceId, createWidgets, &ctx);
|
||||
|
||||
while (true) {
|
||||
task_event_group_wait_any(&event_group, nullptr, portMAX_DELAY);
|
||||
|
||||
bool shouldClose = false;
|
||||
AppEvent event {};
|
||||
if (app_event_await(&sub, &event, portMAX_DELAY) != ERROR_NONE) {
|
||||
break;
|
||||
}
|
||||
if (event.type == APP_EVENT_CLOSE) {
|
||||
break;
|
||||
while (app_event_poll(&sub, &event) == ERROR_NONE) {
|
||||
if (event.type == APP_EVENT_CLOSE) {
|
||||
shouldClose = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (shouldClose) break;
|
||||
}
|
||||
|
||||
window_manager_remove(window);
|
||||
app_event_unsubscribe(&sub);
|
||||
check(app_event_unsubscribe(&sub) == ERROR_NONE);
|
||||
task_event_group_destruct(&event_group);
|
||||
|
||||
return ctx.result;
|
||||
}
|
||||
|
||||
@@ -7,9 +7,11 @@
|
||||
#include <app/event.h>
|
||||
#include <app/manager.h>
|
||||
#include <app/manifest.h>
|
||||
#include <app/scheduler.h>
|
||||
|
||||
#include <lvgl_window_manager/window_manager.h>
|
||||
|
||||
#include <tactility/check.h>
|
||||
#include <tactility/device.h>
|
||||
#include <tactility/drivers/backlight.h>
|
||||
|
||||
@@ -205,34 +207,40 @@ void persistIfUpdated(Context& ctx) {
|
||||
}
|
||||
}
|
||||
|
||||
int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
int32_t appMain(int argc, char* argv[]) {
|
||||
uint32_t appInstanceId = app_scheduler_current_app_id();
|
||||
Context ctx {};
|
||||
ctx.appInstanceId = appInstanceId;
|
||||
|
||||
TaskEventGroup event_group {};
|
||||
task_event_group_construct(&event_group);
|
||||
|
||||
AppEventSubscription sub {};
|
||||
sub.app_instance_id = appInstanceId;
|
||||
app_event_subscribe(&sub);
|
||||
check(app_event_subscribe(&sub, &event_group) == ERROR_NONE);
|
||||
|
||||
WindowId window = window_manager_create(appInstanceId, createWidgets, &ctx);
|
||||
|
||||
bool shouldClose = false;
|
||||
while (!shouldClose) {
|
||||
task_event_group_wait_any(&event_group, nullptr, portMAX_DELAY);
|
||||
|
||||
AppEvent event {};
|
||||
if (app_event_await(&sub, &event, portMAX_DELAY) != ERROR_NONE) {
|
||||
break;
|
||||
}
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
persistIfUpdated(ctx);
|
||||
shouldClose = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
while (app_event_poll(&sub, &event) == ERROR_NONE) {
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
persistIfUpdated(ctx);
|
||||
shouldClose = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (shouldClose) break;
|
||||
}
|
||||
}
|
||||
|
||||
window_manager_remove(window);
|
||||
app_event_unsubscribe(&sub);
|
||||
check(app_event_unsubscribe(&sub) == ERROR_NONE);
|
||||
task_event_group_destruct(&event_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <app/event.h>
|
||||
#include <app/manager.h>
|
||||
#include <app/manifest.h>
|
||||
#include <app/scheduler.h>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
@@ -14,6 +15,7 @@
|
||||
|
||||
#include <lvgl_window_manager/window_manager.h>
|
||||
|
||||
#include <tactility/check.h>
|
||||
#include <tactility/device.h>
|
||||
#include <tactility/drivers/power_supply.h>
|
||||
#include <tactility/log.h>
|
||||
@@ -231,29 +233,37 @@ void runAutoStart() {
|
||||
}
|
||||
}
|
||||
|
||||
int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
int32_t appMain(int argc, char* argv[]) {
|
||||
uint32_t appInstanceId = app_scheduler_current_app_id();
|
||||
runAutoStart();
|
||||
|
||||
TaskEventGroup event_group {};
|
||||
task_event_group_construct(&event_group);
|
||||
|
||||
AppEventSubscription sub {};
|
||||
sub.app_instance_id = appInstanceId;
|
||||
app_event_subscribe(&sub);
|
||||
check(app_event_subscribe(&sub, &event_group) == ERROR_NONE);
|
||||
|
||||
WindowId window = window_manager_create(appInstanceId, createWidgets, nullptr);
|
||||
|
||||
// The launcher is meant to stay resident (it's the home screen) - it only gives up its
|
||||
// thread when app-module's scheduler asks it to (e.g. another new-model app is started).
|
||||
while (true) {
|
||||
task_event_group_wait_any(&event_group, nullptr, portMAX_DELAY);
|
||||
|
||||
bool shouldClose = false;
|
||||
AppEvent event {};
|
||||
if (app_event_await(&sub, &event, portMAX_DELAY) != ERROR_NONE) {
|
||||
break;
|
||||
}
|
||||
if (event.type == APP_EVENT_CLOSE) {
|
||||
break;
|
||||
while (app_event_poll(&sub, &event) == ERROR_NONE) {
|
||||
if (event.type == APP_EVENT_CLOSE) {
|
||||
shouldClose = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (shouldClose) break;
|
||||
}
|
||||
|
||||
window_manager_remove(window);
|
||||
app_event_unsubscribe(&sub);
|
||||
check(app_event_unsubscribe(&sub) == ERROR_NONE);
|
||||
task_event_group_destruct(&event_group);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,9 +9,12 @@
|
||||
#include <app/event.h>
|
||||
#include <app/manager.h>
|
||||
#include <app/manifest.h>
|
||||
#include <app/scheduler.h>
|
||||
|
||||
#include <lvgl_window_manager/window_manager.h>
|
||||
|
||||
#include <tactility/check.h>
|
||||
|
||||
#include <lvgl/widgets/toolbar.h>
|
||||
|
||||
#include <lvgl.h>
|
||||
@@ -141,33 +144,39 @@ void createWidgets(lv_obj_t* parent, void* userData) {
|
||||
lv_obj_add_event_cb(ctx->languageDropdown, onLanguageSet, LV_EVENT_VALUE_CHANGED, ctx);
|
||||
}
|
||||
|
||||
int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
int32_t appMain(int argc, char* argv[]) {
|
||||
uint32_t appInstanceId = app_scheduler_current_app_id();
|
||||
Context ctx;
|
||||
ctx.appInstanceId = appInstanceId;
|
||||
|
||||
TaskEventGroup event_group {};
|
||||
task_event_group_construct(&event_group);
|
||||
|
||||
AppEventSubscription sub {};
|
||||
sub.app_instance_id = appInstanceId;
|
||||
app_event_subscribe(&sub);
|
||||
check(app_event_subscribe(&sub, &event_group) == ERROR_NONE);
|
||||
|
||||
WindowId window = window_manager_create(appInstanceId, createWidgets, &ctx);
|
||||
|
||||
bool shouldClose = false;
|
||||
while (!shouldClose) {
|
||||
task_event_group_wait_any(&event_group, nullptr, portMAX_DELAY);
|
||||
|
||||
AppEvent event {};
|
||||
if (app_event_await(&sub, &event, portMAX_DELAY) != ERROR_NONE) {
|
||||
break;
|
||||
}
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
while (app_event_poll(&sub, &event) == ERROR_NONE) {
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (shouldClose) break;
|
||||
}
|
||||
}
|
||||
|
||||
window_manager_remove(window);
|
||||
app_event_unsubscribe(&sub);
|
||||
check(app_event_unsubscribe(&sub) == ERROR_NONE);
|
||||
task_event_group_destruct(&event_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -5,12 +5,14 @@
|
||||
#include <app/event.h>
|
||||
#include <app/manager.h>
|
||||
#include <app/manifest.h>
|
||||
#include <app/scheduler.h>
|
||||
|
||||
#include <lvgl_window_manager/window_manager.h>
|
||||
|
||||
#include <lvgl.h>
|
||||
#include <lvgl/lvgl.h>
|
||||
#include <lvgl/widgets/toolbar.h>
|
||||
#include <tactility/check.h>
|
||||
#include <tactility/log.h>
|
||||
|
||||
namespace tt::app::notes {
|
||||
@@ -182,7 +184,8 @@ void createWidgets(lv_obj_t* parent, void* userData) {
|
||||
}
|
||||
}
|
||||
|
||||
int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
int32_t appMain(int argc, char* argv[]) {
|
||||
uint32_t appInstanceId = app_scheduler_current_app_id();
|
||||
|
||||
Context ctx {};
|
||||
ctx.appInstanceId = appInstanceId;
|
||||
@@ -190,51 +193,56 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
ctx.filePath = argv[0];
|
||||
}
|
||||
|
||||
TaskEventGroup event_group {};
|
||||
task_event_group_construct(&event_group);
|
||||
|
||||
AppEventSubscription sub {};
|
||||
sub.app_instance_id = appInstanceId;
|
||||
app_event_subscribe(&sub);
|
||||
check(app_event_subscribe(&sub, &event_group) == ERROR_NONE);
|
||||
|
||||
WindowId window = window_manager_create(appInstanceId, createWidgets, &ctx);
|
||||
|
||||
bool shouldClose = false;
|
||||
while (!shouldClose) {
|
||||
task_event_group_wait_any(&event_group, nullptr, portMAX_DELAY);
|
||||
|
||||
AppEvent event {};
|
||||
if (app_event_await(&sub, &event, portMAX_DELAY) != ERROR_NONE) {
|
||||
break;
|
||||
}
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
case APP_EVENT_RESULT:
|
||||
LOG_I(TAG, "Result for launch id %u", event.result.launch_id);
|
||||
if (event.result.launch_id == ctx.loadFileLaunchId) {
|
||||
ctx.loadFileLaunchId = 0;
|
||||
if (event.result.result == 0 /* Ok */) {
|
||||
auto path = fileselection::getLastPath();
|
||||
if (!path.empty()) {
|
||||
openFile(&ctx, path);
|
||||
while (app_event_poll(&sub, &event) == ERROR_NONE) {
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
case APP_EVENT_RESULT:
|
||||
LOG_I(TAG, "Result for launch id %u", event.result.launch_id);
|
||||
if (event.result.launch_id == ctx.loadFileLaunchId) {
|
||||
ctx.loadFileLaunchId = 0;
|
||||
if (event.result.result == 0 /* Ok */) {
|
||||
auto path = fileselection::getLastPath();
|
||||
if (!path.empty()) {
|
||||
openFile(&ctx, path);
|
||||
}
|
||||
}
|
||||
} else if (event.result.launch_id == ctx.saveFileLaunchId) {
|
||||
ctx.saveFileLaunchId = 0;
|
||||
if (event.result.result == 0 /* Ok */) {
|
||||
auto path = fileselection::getLastPath();
|
||||
// Must re-open file, because the UI was cleared after opening the dialog.
|
||||
if (!path.empty() && saveFile(&ctx, path)) {
|
||||
openFile(&ctx, path);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (event.result.launch_id == ctx.saveFileLaunchId) {
|
||||
ctx.saveFileLaunchId = 0;
|
||||
if (event.result.result == 0 /* Ok */) {
|
||||
auto path = fileselection::getLastPath();
|
||||
// Must re-open file, because the UI was cleared after opening the dialog.
|
||||
if (!path.empty() && saveFile(&ctx, path)) {
|
||||
openFile(&ctx, path);
|
||||
}
|
||||
}
|
||||
}
|
||||
app_manager_stop(event.result.launch_id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
app_manager_stop(event.result.launch_id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (shouldClose) break;
|
||||
}
|
||||
}
|
||||
|
||||
window_manager_remove(window);
|
||||
app_event_unsubscribe(&sub);
|
||||
check(app_event_unsubscribe(&sub) == ERROR_NONE);
|
||||
task_event_group_destruct(&event_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -4,9 +4,11 @@
|
||||
#include <app/event.h>
|
||||
#include <app/manager.h>
|
||||
#include <app/manifest.h>
|
||||
#include <app/scheduler.h>
|
||||
|
||||
#include <lvgl_window_manager/window_manager.h>
|
||||
|
||||
#include <tactility/check.h>
|
||||
#include <tactility/device.h>
|
||||
#include <tactility/drivers/power_supply.h>
|
||||
#include <tactility/time.h>
|
||||
@@ -229,7 +231,8 @@ void createWidgets(lv_obj_t* parent, void* userData) {
|
||||
}
|
||||
}
|
||||
|
||||
int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
int32_t appMain(int argc, char* argv[]) {
|
||||
uint32_t appInstanceId = app_scheduler_current_app_id();
|
||||
Context ctx {};
|
||||
ctx.appInstanceId = appInstanceId;
|
||||
|
||||
@@ -240,31 +243,36 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
updateUi(&ctx);
|
||||
});
|
||||
|
||||
TaskEventGroup event_group {};
|
||||
task_event_group_construct(&event_group);
|
||||
|
||||
AppEventSubscription sub {};
|
||||
sub.app_instance_id = appInstanceId;
|
||||
app_event_subscribe(&sub);
|
||||
check(app_event_subscribe(&sub, &event_group) == ERROR_NONE);
|
||||
|
||||
WindowId window = window_manager_create(appInstanceId, createWidgets, &ctx);
|
||||
ctx.timer->start();
|
||||
|
||||
bool shouldClose = false;
|
||||
while (!shouldClose) {
|
||||
task_event_group_wait_any(&event_group, nullptr, portMAX_DELAY);
|
||||
|
||||
AppEvent event {};
|
||||
if (app_event_await(&sub, &event, portMAX_DELAY) != ERROR_NONE) {
|
||||
break;
|
||||
}
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
while (app_event_poll(&sub, &event) == ERROR_NONE) {
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (shouldClose) break;
|
||||
}
|
||||
}
|
||||
|
||||
ctx.timer->stop();
|
||||
window_manager_remove(window);
|
||||
app_event_unsubscribe(&sub);
|
||||
check(app_event_unsubscribe(&sub) == ERROR_NONE);
|
||||
task_event_group_destruct(&event_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -4,11 +4,13 @@
|
||||
#include <app/event.h>
|
||||
#include <app/manager.h>
|
||||
#include <app/manifest.h>
|
||||
#include <app/scheduler.h>
|
||||
|
||||
#include <lvgl_window_manager/window_manager.h>
|
||||
|
||||
#include <lvgl.h>
|
||||
#include <lvgl/fonts.h>
|
||||
#include <tactility/check.h>
|
||||
#include <tactility/device.h>
|
||||
#include <tactility/drivers/power_supply.h>
|
||||
|
||||
@@ -132,22 +134,25 @@ void createWidgets(lv_obj_t* parent, void* userData) {
|
||||
lv_obj_add_event_cb(no_button, onNoPressed, LV_EVENT_SHORT_CLICKED, ctx);
|
||||
}
|
||||
|
||||
int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
int32_t appMain(int argc, char* argv[]) {
|
||||
uint32_t appInstanceId = app_scheduler_current_app_id();
|
||||
Context ctx {};
|
||||
ctx.appInstanceId = appInstanceId;
|
||||
|
||||
TaskEventGroup event_group {};
|
||||
task_event_group_construct(&event_group);
|
||||
|
||||
AppEventSubscription sub {};
|
||||
sub.app_instance_id = appInstanceId;
|
||||
app_event_subscribe(&sub);
|
||||
check(app_event_subscribe(&sub, &event_group) == ERROR_NONE);
|
||||
|
||||
WindowId window = window_manager_create(appInstanceId, createWidgets, &ctx);
|
||||
|
||||
bool shouldClose = false;
|
||||
while (!shouldClose) {
|
||||
task_event_group_wait_any(&event_group, nullptr, portMAX_DELAY);
|
||||
|
||||
AppEvent event {};
|
||||
if (app_event_await(&sub, &event, portMAX_DELAY) != ERROR_NONE) {
|
||||
break;
|
||||
}
|
||||
while (app_event_poll(&sub, &event) == ERROR_NONE) {
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
@@ -155,10 +160,13 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (shouldClose) break;
|
||||
}
|
||||
}
|
||||
|
||||
window_manager_remove(window);
|
||||
app_event_unsubscribe(&sub);
|
||||
check(app_event_unsubscribe(&sub) == ERROR_NONE);
|
||||
task_event_group_destruct(&event_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -12,9 +12,11 @@
|
||||
#include <app/event.h>
|
||||
#include <app/manager.h>
|
||||
#include <app/manifest.h>
|
||||
#include <app/scheduler.h>
|
||||
|
||||
#include <lvgl_window_manager/window_manager.h>
|
||||
|
||||
#include <tactility/check.h>
|
||||
#include <tactility/log.h>
|
||||
|
||||
#include <lvgl.h>
|
||||
@@ -240,7 +242,8 @@ void createWidgets(lv_obj_t* parent, void* userData) {
|
||||
}
|
||||
}
|
||||
|
||||
int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
int32_t appMain(int argc, char* argv[]) {
|
||||
uint32_t appInstanceId = app_scheduler_current_app_id();
|
||||
Context ctx {};
|
||||
ctx.appInstanceId = appInstanceId;
|
||||
ctx.updateTimer = std::make_unique<Timer>(Timer::Type::Periodic, 500 / portTICK_PERIOD_MS, [&ctx] {
|
||||
@@ -250,24 +253,28 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
}
|
||||
});
|
||||
|
||||
TaskEventGroup event_group {};
|
||||
task_event_group_construct(&event_group);
|
||||
|
||||
AppEventSubscription sub {};
|
||||
sub.app_instance_id = appInstanceId;
|
||||
app_event_subscribe(&sub);
|
||||
check(app_event_subscribe(&sub, &event_group) == ERROR_NONE);
|
||||
|
||||
WindowId window = window_manager_create(appInstanceId, createWidgets, &ctx);
|
||||
|
||||
bool shouldClose = false;
|
||||
while (!shouldClose) {
|
||||
task_event_group_wait_any(&event_group, nullptr, portMAX_DELAY);
|
||||
|
||||
AppEvent event {};
|
||||
if (app_event_await(&sub, &event, portMAX_DELAY) != ERROR_NONE) {
|
||||
break;
|
||||
}
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
while (app_event_poll(&sub, &event) == ERROR_NONE) {
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (shouldClose) break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -276,7 +283,8 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
}
|
||||
|
||||
window_manager_remove(window);
|
||||
app_event_unsubscribe(&sub);
|
||||
check(app_event_unsubscribe(&sub) == ERROR_NONE);
|
||||
task_event_group_destruct(&event_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3,9 +3,11 @@
|
||||
#include <app/event.h>
|
||||
#include <app/manager.h>
|
||||
#include <app/manifest.h>
|
||||
#include <app/scheduler.h>
|
||||
|
||||
#include <lvgl_window_manager/window_manager.h>
|
||||
|
||||
#include <tactility/check.h>
|
||||
#include <tactility/log.h>
|
||||
|
||||
#include <lvgl.h>
|
||||
@@ -99,29 +101,37 @@ void createWidgets(lv_obj_t* parent, void* userData) {
|
||||
}
|
||||
}
|
||||
|
||||
int32_t appMain(AppInstanceId appInstanceId, int argc, char* argv[]) {
|
||||
int32_t appMain(int argc, char* argv[]) {
|
||||
AppInstanceId appInstanceId = app_scheduler_current_app_id();
|
||||
Context ctx { appInstanceId };
|
||||
ctx.argc = argc;
|
||||
ctx.argv = argv;
|
||||
|
||||
TaskEventGroup event_group {};
|
||||
task_event_group_construct(&event_group);
|
||||
|
||||
AppEventSubscription sub {};
|
||||
sub.app_instance_id = appInstanceId;
|
||||
app_event_subscribe(&sub);
|
||||
check(app_event_subscribe(&sub, &event_group) == ERROR_NONE);
|
||||
|
||||
WindowId window = window_manager_create(appInstanceId, createWidgets, &ctx);
|
||||
|
||||
while (true) {
|
||||
task_event_group_wait_any(&event_group, nullptr, portMAX_DELAY);
|
||||
|
||||
bool shouldClose = false;
|
||||
AppEvent event {};
|
||||
if (app_event_await(&sub, &event, portMAX_DELAY) != ERROR_NONE) {
|
||||
break;
|
||||
}
|
||||
if (event.type == APP_EVENT_CLOSE) {
|
||||
break;
|
||||
while (app_event_poll(&sub, &event) == ERROR_NONE) {
|
||||
if (event.type == APP_EVENT_CLOSE) {
|
||||
shouldClose = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (shouldClose) break;
|
||||
}
|
||||
|
||||
window_manager_remove(window);
|
||||
app_event_unsubscribe(&sub);
|
||||
check(app_event_unsubscribe(&sub) == ERROR_NONE);
|
||||
task_event_group_destruct(&event_group);
|
||||
|
||||
return ctx.result;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <app/event.h>
|
||||
#include <app/manager.h>
|
||||
#include <app/manifest.h>
|
||||
#include <app/scheduler.h>
|
||||
|
||||
#include <lvgl_window_manager/window_manager.h>
|
||||
|
||||
@@ -76,27 +77,35 @@ void createWidgets(lv_obj_t* parent, void*) {
|
||||
}
|
||||
}
|
||||
|
||||
int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
int32_t appMain(int argc, char* argv[]) {
|
||||
uint32_t appInstanceId = app_scheduler_current_app_id();
|
||||
settingsInstanceId = appInstanceId;
|
||||
|
||||
TaskEventGroup event_group {};
|
||||
task_event_group_construct(&event_group);
|
||||
|
||||
AppEventSubscription sub {};
|
||||
sub.app_instance_id = appInstanceId;
|
||||
app_event_subscribe(&sub);
|
||||
check(app_event_subscribe(&sub, &event_group) == ERROR_NONE);
|
||||
|
||||
WindowId window = window_manager_create(appInstanceId, createWidgets, nullptr);
|
||||
|
||||
while (true) {
|
||||
task_event_group_wait_any(&event_group, nullptr, portMAX_DELAY);
|
||||
|
||||
bool shouldClose = false;
|
||||
AppEvent event {};
|
||||
if (app_event_await(&sub, &event, portMAX_DELAY) != ERROR_NONE) {
|
||||
break;
|
||||
}
|
||||
if (event.type == APP_EVENT_CLOSE) {
|
||||
break;
|
||||
while (app_event_poll(&sub, &event) == ERROR_NONE) {
|
||||
if (event.type == APP_EVENT_CLOSE) {
|
||||
shouldClose = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (shouldClose) break;
|
||||
}
|
||||
|
||||
window_manager_remove(window);
|
||||
app_event_unsubscribe(&sub);
|
||||
check(app_event_unsubscribe(&sub) == ERROR_NONE);
|
||||
task_event_group_destruct(&event_group);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,9 +11,11 @@
|
||||
#include <app/event.h>
|
||||
#include <app/manager.h>
|
||||
#include <app/manifest.h>
|
||||
#include <app/scheduler.h>
|
||||
|
||||
#include <lvgl_window_manager/window_manager.h>
|
||||
|
||||
#include <tactility/check.h>
|
||||
#include <tactility/log.h>
|
||||
|
||||
#include <lvgl/fonts.h>
|
||||
@@ -159,7 +161,7 @@ void onContinueClicked(lv_event_t* event) {
|
||||
markCompleted();
|
||||
// Async, non-blocking - must NOT call app_manager_stop() directly here: this
|
||||
// callback runs ON the LVGL task, and app-lifecycle transitions must happen on this
|
||||
// app's own thread (woken via app_event_await()), which closes by returning.
|
||||
// app's own thread (woken via app_event_poll()), which closes by returning.
|
||||
AppEvent closeEvent { .type = APP_EVENT_CLOSE, .timestamp = 0, .result = {} };
|
||||
app_event_emit(ctx->appInstanceId, &closeEvent);
|
||||
break;
|
||||
@@ -203,7 +205,8 @@ void createWidgets(lv_obj_t* parent, void* userData) {
|
||||
renderCurrent(ctx);
|
||||
}
|
||||
|
||||
int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
int32_t appMain(int argc, char* argv[]) {
|
||||
uint32_t appInstanceId = app_scheduler_current_app_id();
|
||||
Context ctx {};
|
||||
ctx.appInstanceId = appInstanceId;
|
||||
ctx.steps = {
|
||||
@@ -229,36 +232,41 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
}
|
||||
};
|
||||
|
||||
TaskEventGroup event_group {};
|
||||
task_event_group_construct(&event_group);
|
||||
|
||||
AppEventSubscription sub {};
|
||||
sub.app_instance_id = appInstanceId;
|
||||
app_event_subscribe(&sub);
|
||||
check(app_event_subscribe(&sub, &event_group) == ERROR_NONE);
|
||||
|
||||
WindowId window = window_manager_create(appInstanceId, createWidgets, &ctx);
|
||||
|
||||
bool shouldClose = false;
|
||||
while (!shouldClose) {
|
||||
task_event_group_wait_any(&event_group, nullptr, portMAX_DELAY);
|
||||
|
||||
AppEvent event {};
|
||||
if (app_event_await(&sub, &event, portMAX_DELAY) != ERROR_NONE) {
|
||||
break;
|
||||
}
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
case APP_EVENT_RESULT:
|
||||
if (event.result.launch_id == ctx.pendingStepDialogId) {
|
||||
ctx.pendingStepDialogId = 0;
|
||||
advanceTo(&ctx, ctx.stepIndex + 1);
|
||||
}
|
||||
app_manager_stop(event.result.launch_id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
while (app_event_poll(&sub, &event) == ERROR_NONE) {
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
case APP_EVENT_RESULT:
|
||||
if (event.result.launch_id == ctx.pendingStepDialogId) {
|
||||
ctx.pendingStepDialogId = 0;
|
||||
advanceTo(&ctx, ctx.stepIndex + 1);
|
||||
}
|
||||
app_manager_stop(event.result.launch_id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (shouldClose) break;
|
||||
}
|
||||
}
|
||||
|
||||
window_manager_remove(window);
|
||||
app_event_unsubscribe(&sub);
|
||||
check(app_event_unsubscribe(&sub) == ERROR_NONE);
|
||||
task_event_group_destruct(&event_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <tactility/check.h>
|
||||
#include "tactility/time.h"
|
||||
|
||||
#include <Tactility/DeprecatedPaths.h>
|
||||
@@ -8,6 +9,7 @@
|
||||
#include <app/event.h>
|
||||
#include <app/manager.h>
|
||||
#include <app/manifest.h>
|
||||
#include <app/scheduler.h>
|
||||
|
||||
#include <lvgl_window_manager/window_manager.h>
|
||||
|
||||
@@ -399,7 +401,8 @@ void createWidgets(lv_obj_t* parent, void* userData) {
|
||||
updateTasks(ctx);
|
||||
}
|
||||
|
||||
int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
int32_t appMain(int argc, char* argv[]) {
|
||||
uint32_t appInstanceId = app_scheduler_current_app_id();
|
||||
Context ctx {};
|
||||
ctx.appInstanceId = appInstanceId;
|
||||
|
||||
@@ -417,9 +420,11 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
lvgl_unlock();
|
||||
});
|
||||
|
||||
TaskEventGroup event_group {};
|
||||
task_event_group_construct(&event_group);
|
||||
|
||||
AppEventSubscription sub {};
|
||||
sub.app_instance_id = appInstanceId;
|
||||
app_event_subscribe(&sub);
|
||||
check(app_event_subscribe(&sub, &event_group) == ERROR_NONE);
|
||||
|
||||
WindowId window = window_manager_create(appInstanceId, createWidgets, &ctx);
|
||||
ctx.memoryTimer->start(); // Memory: every 10s
|
||||
@@ -427,23 +432,26 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
|
||||
bool shouldClose = false;
|
||||
while (!shouldClose) {
|
||||
task_event_group_wait_any(&event_group, nullptr, portMAX_DELAY);
|
||||
|
||||
AppEvent event {};
|
||||
if (app_event_await(&sub, &event, portMAX_DELAY) != ERROR_NONE) {
|
||||
break;
|
||||
}
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
while (app_event_poll(&sub, &event) == ERROR_NONE) {
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (shouldClose) break;
|
||||
}
|
||||
}
|
||||
|
||||
ctx.memoryTimer->stop();
|
||||
ctx.tasksTimer->stop();
|
||||
window_manager_remove(window);
|
||||
app_event_unsubscribe(&sub);
|
||||
check(app_event_unsubscribe(&sub) == ERROR_NONE);
|
||||
task_event_group_destruct(&event_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -6,9 +6,11 @@
|
||||
#include <app/event.h>
|
||||
#include <app/manager.h>
|
||||
#include <app/manifest.h>
|
||||
#include <app/scheduler.h>
|
||||
|
||||
#include <lvgl_window_manager/window_manager.h>
|
||||
|
||||
#include <tactility/check.h>
|
||||
#include <tactility/log.h>
|
||||
|
||||
#include <lvgl/lvgl.h>
|
||||
@@ -153,48 +155,54 @@ void createWidgets(lv_obj_t* parent, void* userData) {
|
||||
lv_label_set_text(ctx->timeZoneLabel, timeZoneName.c_str());
|
||||
}
|
||||
|
||||
int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
int32_t appMain(int argc, char* argv[]) {
|
||||
uint32_t appInstanceId = app_scheduler_current_app_id();
|
||||
Context ctx {};
|
||||
ctx.appInstanceId = appInstanceId;
|
||||
|
||||
TaskEventGroup event_group {};
|
||||
task_event_group_construct(&event_group);
|
||||
|
||||
AppEventSubscription sub {};
|
||||
sub.app_instance_id = appInstanceId;
|
||||
app_event_subscribe(&sub);
|
||||
check(app_event_subscribe(&sub, &event_group) == ERROR_NONE);
|
||||
|
||||
WindowId window = window_manager_create(appInstanceId, createWidgets, &ctx);
|
||||
|
||||
bool shouldClose = false;
|
||||
while (!shouldClose) {
|
||||
task_event_group_wait_any(&event_group, nullptr, portMAX_DELAY);
|
||||
|
||||
AppEvent event {};
|
||||
if (app_event_await(&sub, &event, portMAX_DELAY) != ERROR_NONE) {
|
||||
break;
|
||||
}
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
case APP_EVENT_RESULT:
|
||||
if (event.result.launch_id == ctx.pendingTimeZoneDialogId) {
|
||||
ctx.pendingTimeZoneDialogId = 0;
|
||||
if (event.result.result == 0 /* Ok */) {
|
||||
const auto name = timezone::getLastName();
|
||||
LOG_I(TAG, "Result name=%s code=%s", name.c_str(), timezone::getLastCode().c_str());
|
||||
if (!name.empty()) {
|
||||
lvgl_lock();
|
||||
lv_label_set_text(ctx.timeZoneLabel, name.c_str());
|
||||
lvgl_unlock();
|
||||
while (app_event_poll(&sub, &event) == ERROR_NONE) {
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
case APP_EVENT_RESULT:
|
||||
if (event.result.launch_id == ctx.pendingTimeZoneDialogId) {
|
||||
ctx.pendingTimeZoneDialogId = 0;
|
||||
if (event.result.result == 0 /* Ok */) {
|
||||
const auto name = timezone::getLastName();
|
||||
LOG_I(TAG, "Result name=%s code=%s", name.c_str(), timezone::getLastCode().c_str());
|
||||
if (!name.empty()) {
|
||||
lvgl_lock();
|
||||
lv_label_set_text(ctx.timeZoneLabel, name.c_str());
|
||||
lvgl_unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
app_manager_stop(event.result.launch_id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
app_manager_stop(event.result.launch_id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (shouldClose) break;
|
||||
}
|
||||
}
|
||||
|
||||
window_manager_remove(window);
|
||||
app_event_unsubscribe(&sub);
|
||||
check(app_event_unsubscribe(&sub) == ERROR_NONE);
|
||||
task_event_group_destruct(&event_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -9,9 +9,11 @@
|
||||
#include <app/event.h>
|
||||
#include <app/manager.h>
|
||||
#include <app/manifest.h>
|
||||
#include <app/scheduler.h>
|
||||
|
||||
#include <lvgl_window_manager/window_manager.h>
|
||||
|
||||
#include <tactility/check.h>
|
||||
#include <tactility/log.h>
|
||||
|
||||
#include <lvgl/lvgl.h>
|
||||
@@ -229,7 +231,8 @@ void createWidgets(lv_obj_t* parent, void* userData) {
|
||||
ctx->listWidget = list;
|
||||
}
|
||||
|
||||
int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
int32_t appMain(int argc, char* argv[]) {
|
||||
uint32_t appInstanceId = app_scheduler_current_app_id();
|
||||
// argv layout: [0]="1"/"0" (saveTimeZone).
|
||||
|
||||
Context ctx;
|
||||
@@ -240,26 +243,33 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
updateList(&ctx);
|
||||
});
|
||||
|
||||
TaskEventGroup event_group {};
|
||||
task_event_group_construct(&event_group);
|
||||
|
||||
AppEventSubscription sub {};
|
||||
sub.app_instance_id = appInstanceId;
|
||||
app_event_subscribe(&sub);
|
||||
check(app_event_subscribe(&sub, &event_group) == ERROR_NONE);
|
||||
|
||||
WindowId window = window_manager_create(appInstanceId, createWidgets, &ctx);
|
||||
ctx.updateTimer->start();
|
||||
|
||||
while (true) {
|
||||
task_event_group_wait_any(&event_group, nullptr, portMAX_DELAY);
|
||||
|
||||
bool shouldClose = false;
|
||||
AppEvent event {};
|
||||
if (app_event_await(&sub, &event, portMAX_DELAY) != ERROR_NONE) {
|
||||
break;
|
||||
}
|
||||
if (event.type == APP_EVENT_CLOSE) {
|
||||
break;
|
||||
while (app_event_poll(&sub, &event) == ERROR_NONE) {
|
||||
if (event.type == APP_EVENT_CLOSE) {
|
||||
shouldClose = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (shouldClose) break;
|
||||
}
|
||||
|
||||
ctx.updateTimer->stop();
|
||||
window_manager_remove(window);
|
||||
app_event_unsubscribe(&sub);
|
||||
check(app_event_unsubscribe(&sub) == ERROR_NONE);
|
||||
task_event_group_destruct(&event_group);
|
||||
|
||||
return ctx.result;
|
||||
}
|
||||
|
||||
@@ -8,9 +8,11 @@
|
||||
#include <app/event.h>
|
||||
#include <app/manager.h>
|
||||
#include <app/manifest.h>
|
||||
#include <app/scheduler.h>
|
||||
|
||||
#include <lvgl_window_manager/window_manager.h>
|
||||
|
||||
#include <tactility/check.h>
|
||||
#include <tactility/log.h>
|
||||
#include <lvgl/lvgl.h>
|
||||
#include <lvgl/devices/pointer.h>
|
||||
@@ -174,7 +176,7 @@ void onPress(lv_event_t* event) {
|
||||
|
||||
// Async, non-blocking - must NOT call app_manager_stop() directly here: this callback runs
|
||||
// ON the LVGL task, and app-lifecycle transitions must happen on this app's own thread
|
||||
// (woken up via app_event_await() below), which closes by returning. The result (Ok/Error)
|
||||
// (woken up via app_event_poll() below), which closes by returning. The result (Ok/Error)
|
||||
// is reported by appMain() itself when it returns, based on ctx.calibrationApplied.
|
||||
AppEvent closeEvent { .type = APP_EVENT_CLOSE, .timestamp = 0, .result = {} };
|
||||
app_event_emit(ctx->appInstanceId, &closeEvent);
|
||||
@@ -221,7 +223,8 @@ void createWidgets(lv_obj_t* parent, void* userData) {
|
||||
updateUi(ctx);
|
||||
}
|
||||
|
||||
int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
int32_t appMain(int argc, char* argv[]) {
|
||||
uint32_t appInstanceId = app_scheduler_current_app_id();
|
||||
Context ctx {};
|
||||
ctx.appInstanceId = appInstanceId;
|
||||
|
||||
@@ -233,29 +236,34 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
}
|
||||
lvgl_unlock();
|
||||
|
||||
TaskEventGroup event_group {};
|
||||
task_event_group_construct(&event_group);
|
||||
|
||||
AppEventSubscription sub {};
|
||||
sub.app_instance_id = appInstanceId;
|
||||
app_event_subscribe(&sub);
|
||||
check(app_event_subscribe(&sub, &event_group) == ERROR_NONE);
|
||||
|
||||
WindowId window = window_manager_create(appInstanceId, createWidgets, &ctx);
|
||||
|
||||
bool shouldClose = false;
|
||||
while (!shouldClose) {
|
||||
task_event_group_wait_any(&event_group, nullptr, portMAX_DELAY);
|
||||
|
||||
AppEvent event {};
|
||||
if (app_event_await(&sub, &event, portMAX_DELAY) != ERROR_NONE) {
|
||||
break;
|
||||
}
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
while (app_event_poll(&sub, &event) == ERROR_NONE) {
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (shouldClose) break;
|
||||
}
|
||||
}
|
||||
|
||||
window_manager_remove(window);
|
||||
app_event_unsubscribe(&sub);
|
||||
check(app_event_unsubscribe(&sub) == ERROR_NONE);
|
||||
task_event_group_destruct(&event_group);
|
||||
|
||||
// finishCalibration() already applied a new calibration on success. On cancel/failure,
|
||||
// restore whatever calibration was on disk before the block above cleared it.
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <lvgl/lvgl.h>
|
||||
#include <lvgl/widgets/toolbar.h>
|
||||
|
||||
#include <tactility/check.h>
|
||||
#include <tactility/drivers/trackball.h>
|
||||
|
||||
#include <Tactility/Assets.h>
|
||||
@@ -14,6 +15,7 @@
|
||||
#include <app/event.h>
|
||||
#include <app/manager.h>
|
||||
#include <app/manifest.h>
|
||||
#include <app/scheduler.h>
|
||||
|
||||
#include <lvgl_window_manager/window_manager.h>
|
||||
|
||||
@@ -268,34 +270,40 @@ void persistIfUpdated(Context& ctx) {
|
||||
}
|
||||
}
|
||||
|
||||
int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
int32_t appMain(int argc, char* argv[]) {
|
||||
uint32_t appInstanceId = app_scheduler_current_app_id();
|
||||
Context ctx {};
|
||||
ctx.appInstanceId = appInstanceId;
|
||||
|
||||
TaskEventGroup event_group {};
|
||||
task_event_group_construct(&event_group);
|
||||
|
||||
AppEventSubscription sub {};
|
||||
sub.app_instance_id = appInstanceId;
|
||||
app_event_subscribe(&sub);
|
||||
check(app_event_subscribe(&sub, &event_group) == ERROR_NONE);
|
||||
|
||||
WindowId window = window_manager_create(appInstanceId, createWidgets, &ctx);
|
||||
|
||||
bool shouldClose = false;
|
||||
while (!shouldClose) {
|
||||
task_event_group_wait_any(&event_group, nullptr, portMAX_DELAY);
|
||||
|
||||
AppEvent event {};
|
||||
if (app_event_await(&sub, &event, portMAX_DELAY) != ERROR_NONE) {
|
||||
break;
|
||||
}
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
persistIfUpdated(ctx);
|
||||
shouldClose = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
while (app_event_poll(&sub, &event) == ERROR_NONE) {
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
persistIfUpdated(ctx);
|
||||
shouldClose = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (shouldClose) break;
|
||||
}
|
||||
}
|
||||
|
||||
window_manager_remove(window);
|
||||
app_event_unsubscribe(&sub);
|
||||
check(app_event_unsubscribe(&sub) == ERROR_NONE);
|
||||
task_event_group_destruct(&event_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3,9 +3,12 @@
|
||||
#include <app/event.h>
|
||||
#include <app/manager.h>
|
||||
#include <app/manifest.h>
|
||||
#include <app/scheduler.h>
|
||||
|
||||
#include <lvgl_window_manager/window_manager.h>
|
||||
|
||||
#include <tactility/check.h>
|
||||
|
||||
#include <lvgl.h>
|
||||
#include <lvgl/widgets/toolbar.h>
|
||||
|
||||
@@ -81,33 +84,39 @@ void createWidgets(lv_obj_t* parent, void* userData) {
|
||||
}
|
||||
}
|
||||
|
||||
int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
int32_t appMain(int argc, char* argv[]) {
|
||||
uint32_t appInstanceId = app_scheduler_current_app_id();
|
||||
Context ctx {};
|
||||
ctx.appInstanceId = appInstanceId;
|
||||
|
||||
TaskEventGroup event_group {};
|
||||
task_event_group_construct(&event_group);
|
||||
|
||||
AppEventSubscription sub {};
|
||||
sub.app_instance_id = appInstanceId;
|
||||
app_event_subscribe(&sub);
|
||||
check(app_event_subscribe(&sub, &event_group) == ERROR_NONE);
|
||||
|
||||
WindowId window = window_manager_create(appInstanceId, createWidgets, &ctx);
|
||||
|
||||
bool shouldClose = false;
|
||||
while (!shouldClose) {
|
||||
task_event_group_wait_any(&event_group, nullptr, portMAX_DELAY);
|
||||
|
||||
AppEvent event {};
|
||||
if (app_event_await(&sub, &event, portMAX_DELAY) != ERROR_NONE) {
|
||||
break;
|
||||
}
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
while (app_event_poll(&sub, &event) == ERROR_NONE) {
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (shouldClose) break;
|
||||
}
|
||||
}
|
||||
|
||||
window_manager_remove(window);
|
||||
app_event_unsubscribe(&sub);
|
||||
check(app_event_unsubscribe(&sub) == ERROR_NONE);
|
||||
task_event_group_destruct(&event_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -8,9 +8,11 @@
|
||||
#include <app/event.h>
|
||||
#include <app/manager.h>
|
||||
#include <app/manifest.h>
|
||||
#include <app/scheduler.h>
|
||||
|
||||
#include <lvgl_window_manager/window_manager.h>
|
||||
|
||||
#include <tactility/check.h>
|
||||
#include <tactility/log.h>
|
||||
|
||||
#include <lvgl.h>
|
||||
@@ -354,7 +356,8 @@ void createWidgets(lv_obj_t* parent, void* userData) {
|
||||
"AP mode uses the password configured above.");
|
||||
}
|
||||
|
||||
int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
int32_t appMain(int argc, char* argv[]) {
|
||||
uint32_t appInstanceId = app_scheduler_current_app_id();
|
||||
Context ctx {};
|
||||
ctx.appInstanceId = appInstanceId;
|
||||
ctx.wsSettings = settings::webserver::loadOrGetDefault();
|
||||
@@ -362,24 +365,28 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
ctx.wsSettings.webServerEnabled = service::webserver::isWebServerEnabled();
|
||||
ctx.originalSettings = ctx.wsSettings;
|
||||
|
||||
TaskEventGroup event_group {};
|
||||
task_event_group_construct(&event_group);
|
||||
|
||||
AppEventSubscription sub {};
|
||||
sub.app_instance_id = appInstanceId;
|
||||
app_event_subscribe(&sub);
|
||||
check(app_event_subscribe(&sub, &event_group) == ERROR_NONE);
|
||||
|
||||
WindowId window = window_manager_create(appInstanceId, createWidgets, &ctx);
|
||||
|
||||
bool shouldClose = false;
|
||||
while (!shouldClose) {
|
||||
task_event_group_wait_any(&event_group, nullptr, portMAX_DELAY);
|
||||
|
||||
AppEvent event {};
|
||||
if (app_event_await(&sub, &event, portMAX_DELAY) != ERROR_NONE) {
|
||||
break;
|
||||
}
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
while (app_event_poll(&sub, &event) == ERROR_NONE) {
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (shouldClose) break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -422,7 +429,8 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
}
|
||||
|
||||
window_manager_remove(window);
|
||||
app_event_unsubscribe(&sub);
|
||||
check(app_event_unsubscribe(&sub) == ERROR_NONE);
|
||||
task_event_group_destruct(&event_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -6,12 +6,15 @@
|
||||
#include <app/event.h>
|
||||
#include <app/manager.h>
|
||||
#include <app/manifest.h>
|
||||
#include <app/scheduler.h>
|
||||
|
||||
#include <lvgl_window_manager/window_manager.h>
|
||||
|
||||
#include <lvgl/lvgl.h>
|
||||
#include <lvgl/widgets/toolbar.h>
|
||||
|
||||
#include <tactility/check.h>
|
||||
#include <tactility/device.h>
|
||||
#include <tactility/log.h>
|
||||
|
||||
namespace tt::app::wifiapsettings {
|
||||
@@ -29,9 +32,14 @@ struct Context {
|
||||
lv_obj_t* busySpinner = nullptr;
|
||||
lv_obj_t* connectButton = nullptr;
|
||||
lv_obj_t* disconnectButton = nullptr;
|
||||
lv_obj_t* autoConnectSwitch = nullptr;
|
||||
lv_obj_t* forgetButton = nullptr;
|
||||
lv_obj_t* autoConnectWrapper = nullptr;
|
||||
|
||||
uint32_t forgetDialogId = 0;
|
||||
PubSub<service::wifi::WifiEvent>::SubscriptionHandle wifiSubscription = nullptr;
|
||||
// Set once in appMain() before subscribing, left null if this device has no WiFi driver
|
||||
Device* wifiDevice = nullptr;
|
||||
WifiEventSubscription wifiEventSub {};
|
||||
};
|
||||
|
||||
|
||||
@@ -41,8 +49,7 @@ void onBackPressed(lv_event_t* event) {
|
||||
auto* ctx = static_cast<Context*>(lv_event_get_user_data(event));
|
||||
// Async, non-blocking - must NOT call app_manager_stop() directly here: that bound-waits
|
||||
// (thread_join) for this app's own thread to finish, which needs the LVGL lock
|
||||
// (window_manager_remove()) - but this callback runs ON the LVGL task, which would
|
||||
// deadlock against itself.
|
||||
// but this callback runs ON the LVGL task, which would deadlock against itself.
|
||||
AppEvent closeEvent { .type = APP_EVENT_CLOSE, .timestamp = 0, .result = {} };
|
||||
app_event_emit(ctx->appInstanceId, &closeEvent);
|
||||
}
|
||||
@@ -104,13 +111,34 @@ void updateBusySpinner(Context* ctx) {
|
||||
}
|
||||
}
|
||||
|
||||
// Touches the filesystem (service::wifi::settings::load()) - callers must not run this on the
|
||||
// LVGL task (see updateViews()'s callers).
|
||||
void updateAutoConnectSection(Context* ctx) {
|
||||
service::wifi::settings::WifiApSettings settings;
|
||||
if (service::wifi::settings::load(ctx->ssid.c_str(), settings)) {
|
||||
if (settings.autoConnect) {
|
||||
lv_obj_add_state(ctx->autoConnectSwitch, LV_STATE_CHECKED);
|
||||
} else {
|
||||
lv_obj_remove_state(ctx->autoConnectSwitch, LV_STATE_CHECKED);
|
||||
}
|
||||
lv_obj_remove_flag(ctx->forgetButton, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_remove_flag(ctx->autoConnectWrapper, LV_OBJ_FLAG_HIDDEN);
|
||||
} else {
|
||||
LOG_W(TAG, "No settings found");
|
||||
lv_obj_add_flag(ctx->forgetButton, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_add_flag(ctx->autoConnectWrapper, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
}
|
||||
|
||||
// Runs on whichever thread calls it, not necessarily the LVGL task
|
||||
void updateViews(Context* ctx) {
|
||||
if (ctx->connectButton == nullptr) {
|
||||
// Buried (e.g. the forget confirmation dialog opened on top) - see destroyWidgets().
|
||||
// Buried (e.g. the forget confirmation dialog opened on top)
|
||||
return;
|
||||
}
|
||||
updateConnectButton(ctx);
|
||||
updateBusySpinner(ctx);
|
||||
updateAutoConnectSection(ctx);
|
||||
}
|
||||
|
||||
void requestViewUpdate(Context* ctx) {
|
||||
@@ -119,13 +147,14 @@ void requestViewUpdate(Context* ctx) {
|
||||
lvgl_unlock();
|
||||
}
|
||||
|
||||
// Runs with the LVGL lock already held, possibly on another app's thread - see
|
||||
// WindowDestroyWidgetsFn's warnings. Must stay lock-free: only nulls pointers.
|
||||
void destroyWidgets(void* userData) {
|
||||
auto* ctx = static_cast<Context*>(userData);
|
||||
ctx->busySpinner = nullptr;
|
||||
ctx->connectButton = nullptr;
|
||||
ctx->disconnectButton = nullptr;
|
||||
ctx->autoConnectSwitch = nullptr;
|
||||
ctx->forgetButton = nullptr;
|
||||
ctx->autoConnectWrapper = nullptr;
|
||||
}
|
||||
|
||||
void createWidgets(lv_obj_t* parent, void* userData) {
|
||||
@@ -162,101 +191,127 @@ void createWidgets(lv_obj_t* parent, void* userData) {
|
||||
|
||||
// Forget
|
||||
|
||||
auto* forget_button = lv_button_create(wrapper);
|
||||
lv_obj_set_width(forget_button, LV_PCT(100));
|
||||
lv_obj_add_event_cb(forget_button, onPressForget, LV_EVENT_SHORT_CLICKED, ctx);
|
||||
auto* forget_button_label = lv_label_create(forget_button);
|
||||
ctx->forgetButton = lv_button_create(wrapper);
|
||||
lv_obj_set_width(ctx->forgetButton, LV_PCT(100));
|
||||
lv_obj_add_event_cb(ctx->forgetButton, onPressForget, LV_EVENT_SHORT_CLICKED, ctx);
|
||||
auto* forget_button_label = lv_label_create(ctx->forgetButton);
|
||||
lv_obj_align(forget_button_label, LV_ALIGN_CENTER, 0, 0);
|
||||
lv_label_set_text(forget_button_label, "Forget");
|
||||
lv_obj_add_flag(ctx->forgetButton, LV_OBJ_FLAG_HIDDEN); // shown by updateAutoConnectSection()
|
||||
|
||||
// Auto-connect
|
||||
|
||||
auto* auto_connect_wrapper = lv_obj_create(wrapper);
|
||||
lv_obj_set_size(auto_connect_wrapper, LV_PCT(100), LV_SIZE_CONTENT);
|
||||
lvgl::obj_set_style_bg_invisible(auto_connect_wrapper);
|
||||
lv_obj_set_style_pad_all(auto_connect_wrapper, 0, LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_border_width(auto_connect_wrapper, 0, LV_STATE_DEFAULT);
|
||||
ctx->autoConnectWrapper = lv_obj_create(wrapper);
|
||||
lv_obj_set_size(ctx->autoConnectWrapper, LV_PCT(100), LV_SIZE_CONTENT);
|
||||
lvgl::obj_set_style_bg_invisible(ctx->autoConnectWrapper);
|
||||
lv_obj_set_style_pad_all(ctx->autoConnectWrapper, 0, LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_border_width(ctx->autoConnectWrapper, 0, LV_STATE_DEFAULT);
|
||||
lv_obj_add_flag(ctx->autoConnectWrapper, LV_OBJ_FLAG_HIDDEN); // shown by updateAutoConnectSection()
|
||||
|
||||
auto* auto_connect_label = lv_label_create(auto_connect_wrapper);
|
||||
auto* auto_connect_label = lv_label_create(ctx->autoConnectWrapper);
|
||||
lv_label_set_text(auto_connect_label, "Auto-connect");
|
||||
lv_obj_align(auto_connect_label, LV_ALIGN_LEFT_MID, 0, 0);
|
||||
|
||||
auto* auto_connect_switch = lv_switch_create(auto_connect_wrapper);
|
||||
lv_obj_add_event_cb(auto_connect_switch, onToggleAutoConnect, LV_EVENT_VALUE_CHANGED, ctx);
|
||||
lv_obj_align(auto_connect_switch, LV_ALIGN_RIGHT_MID, 0, 0);
|
||||
|
||||
service::wifi::settings::WifiApSettings settings;
|
||||
if (service::wifi::settings::load(ctx->ssid.c_str(), settings)) {
|
||||
if (settings.autoConnect) {
|
||||
lv_obj_add_state(auto_connect_switch, LV_STATE_CHECKED);
|
||||
} else {
|
||||
lv_obj_remove_state(auto_connect_switch, LV_STATE_CHECKED);
|
||||
}
|
||||
} else {
|
||||
LOG_W(TAG, "No settings found");
|
||||
lv_obj_add_flag(forget_button, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_add_flag(auto_connect_wrapper, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
|
||||
updateViews(ctx);
|
||||
ctx->autoConnectSwitch = lv_switch_create(ctx->autoConnectWrapper);
|
||||
lv_obj_add_event_cb(ctx->autoConnectSwitch, onToggleAutoConnect, LV_EVENT_VALUE_CHANGED, ctx);
|
||||
lv_obj_align(ctx->autoConnectSwitch, LV_ALIGN_RIGHT_MID, 0, 0);
|
||||
}
|
||||
|
||||
int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
int32_t appMain(int argc, char* argv[]) {
|
||||
uint32_t appInstanceId = app_scheduler_current_app_id();
|
||||
|
||||
Context ctx {};
|
||||
ctx.appInstanceId = appInstanceId;
|
||||
ctx.ssid = (argc > 0) ? argv[0] : std::string();
|
||||
|
||||
AppEventSubscription sub {};
|
||||
sub.app_instance_id = appInstanceId;
|
||||
app_event_subscribe(&sub);
|
||||
TaskEventGroup event_group {};
|
||||
task_event_group_construct(&event_group);
|
||||
|
||||
// Subscribed once here, not in createWidgets(): that callback re-runs on every
|
||||
// burial/resurface rebuild, and re-subscribing there would leak the previous subscription
|
||||
// (and its captured ctx pointer) every time, only the last of which shutdown ever cleans up.
|
||||
ctx.wifiSubscription = service::wifi::getPubsub()->subscribe([&ctx](auto) {
|
||||
requestViewUpdate(&ctx);
|
||||
});
|
||||
AppEventSubscription sub {};
|
||||
check(app_event_subscribe(&sub, &event_group) == ERROR_NONE);
|
||||
|
||||
Device* wifi_device = nullptr;
|
||||
if (device_get_first_by_type(&WIFI_TYPE, &wifi_device) == ERROR_NONE) {
|
||||
if (wifi_event_subscribe(wifi_device, &ctx.wifiEventSub, &event_group) == ERROR_NONE) {
|
||||
ctx.wifiDevice = wifi_device;
|
||||
} else {
|
||||
LOG_W(TAG, "Failed to subscribe to WiFi events");
|
||||
device_put(wifi_device);
|
||||
}
|
||||
} else {
|
||||
LOG_W(TAG, "No WiFi device found");
|
||||
}
|
||||
|
||||
WindowId window = window_manager_create_ext(appInstanceId, createWidgets, destroyWidgets, &ctx);
|
||||
|
||||
// The file-I/O-touching part of the view (updateAutoConnectSection()'s settings::load())
|
||||
// runs here, on this app's own task, not the LVGL task createWidgets()
|
||||
requestViewUpdate(&ctx);
|
||||
|
||||
bool shouldClose = false;
|
||||
while (!shouldClose) {
|
||||
AppEvent event {};
|
||||
if (app_event_await(&sub, &event, portMAX_DELAY) != ERROR_NONE) {
|
||||
break;
|
||||
}
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
case APP_EVENT_RESULT:
|
||||
if (event.result.launch_id == ctx.forgetDialogId && event.result.result == 0) { // 0 = Yes
|
||||
if (!service::wifi::settings::remove(ctx.ssid.c_str())) {
|
||||
LOG_E(TAG, "Failed to remove SSID");
|
||||
} else {
|
||||
LOG_I(TAG, "Removed SSID");
|
||||
if (
|
||||
service::wifi::getRadioState() == service::wifi::RadioState::ConnectionActive &&
|
||||
service::wifi::getConnectionTarget() == ctx.ssid
|
||||
) {
|
||||
service::wifi::disconnect();
|
||||
}
|
||||
shouldClose = true;
|
||||
}
|
||||
TickType_t wait_timeout = (ctx.wifiDevice == nullptr) ? pdMS_TO_TICKS(500) : portMAX_DELAY;
|
||||
task_event_group_wait_any(&event_group, nullptr, wait_timeout);
|
||||
|
||||
if (ctx.wifiDevice == nullptr) {
|
||||
Device* retry_device = nullptr;
|
||||
if (device_get_first_by_type(&WIFI_TYPE, &retry_device) == ERROR_NONE) {
|
||||
if (wifi_event_subscribe(retry_device, &ctx.wifiEventSub, &event_group) == ERROR_NONE) {
|
||||
ctx.wifiDevice = retry_device;
|
||||
} else {
|
||||
device_put(retry_device);
|
||||
}
|
||||
app_manager_stop(event.result.launch_id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
AppEvent event {};
|
||||
while (app_event_poll(&sub, &event) == ERROR_NONE) {
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
case APP_EVENT_RESULT:
|
||||
if (event.result.launch_id == ctx.forgetDialogId && event.result.result == 0) { // 0 = Yes
|
||||
if (!service::wifi::settings::remove(ctx.ssid.c_str())) {
|
||||
LOG_E(TAG, "Failed to remove SSID");
|
||||
} else {
|
||||
LOG_I(TAG, "Removed SSID");
|
||||
if (
|
||||
service::wifi::getRadioState() == service::wifi::RadioState::ConnectionActive &&
|
||||
service::wifi::getConnectionTarget() == ctx.ssid
|
||||
) {
|
||||
service::wifi::disconnect();
|
||||
}
|
||||
shouldClose = true;
|
||||
}
|
||||
}
|
||||
app_manager_stop(event.result.launch_id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (shouldClose) break;
|
||||
}
|
||||
|
||||
if (ctx.wifiDevice != nullptr) {
|
||||
WifiEvent wifi_event {};
|
||||
bool wifi_event_received = false;
|
||||
while (wifi_event_poll(&ctx.wifiEventSub, &wifi_event) == ERROR_NONE) {
|
||||
wifi_event_received = true;
|
||||
}
|
||||
if (wifi_event_received) {
|
||||
requestViewUpdate(&ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx.wifiSubscription != nullptr) {
|
||||
service::wifi::getPubsub()->unsubscribe(ctx.wifiSubscription);
|
||||
if (ctx.wifiDevice != nullptr) {
|
||||
wifi_event_unsubscribe(ctx.wifiDevice, &ctx.wifiEventSub);
|
||||
device_put(ctx.wifiDevice);
|
||||
}
|
||||
window_manager_remove(window);
|
||||
app_event_unsubscribe(&sub);
|
||||
check(app_event_unsubscribe(&sub) == ERROR_NONE);
|
||||
task_event_group_destruct(&event_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <app/event.h>
|
||||
#include <app/manager.h>
|
||||
#include <app/manifest.h>
|
||||
#include <app/scheduler.h>
|
||||
|
||||
#include <lvgl_window_manager/window_manager.h>
|
||||
|
||||
@@ -14,6 +15,8 @@
|
||||
#include <lvgl/widgets/spinner.h>
|
||||
#include <lvgl/widgets/toolbar.h>
|
||||
|
||||
#include <tactility/check.h>
|
||||
#include <tactility/device.h>
|
||||
#include <tactility/log.h>
|
||||
|
||||
#include <lvgl.h>
|
||||
@@ -33,10 +36,6 @@ struct Context {
|
||||
std::string initialSsid;
|
||||
std::string initialPassword;
|
||||
|
||||
// Touched only from the LVGL task: directly by onConnectPressed() (an LVGL event callback,
|
||||
// which already runs with the LVGL lock held), and by onWifiEvent() (a wifi-pubsub
|
||||
// callback running on some other thread) which explicitly wraps its touches in
|
||||
// lvgl_lock()/lvgl_unlock() - see WifiApSettings.cpp for the same convention.
|
||||
bool connecting = false;
|
||||
bool connectionError = false;
|
||||
|
||||
@@ -49,7 +48,9 @@ struct Context {
|
||||
lv_obj_t* connecting_spinner = nullptr;
|
||||
lv_obj_t* connection_error = nullptr;
|
||||
|
||||
PubSub<service::wifi::WifiEvent>::SubscriptionHandle wifiSubscription = nullptr;
|
||||
// Set once in appMain() before subscribing, left null if this device has no WiFi driver
|
||||
Device* wifiDevice = nullptr;
|
||||
WifiEventSubscription wifiEventSub {};
|
||||
};
|
||||
|
||||
|
||||
@@ -61,14 +62,12 @@ void onBackPressed(lv_event_t* event) {
|
||||
auto* ctx = static_cast<Context*>(lv_event_get_user_data(event));
|
||||
// Async, non-blocking - must NOT call app_manager_stop() directly here: that bound-waits
|
||||
// (thread_join) for this app's own thread to finish, which needs the LVGL lock
|
||||
// (window_manager_remove()) - but this callback runs ON the LVGL task, which would
|
||||
// deadlock against itself.
|
||||
// but this callback runs ON the LVGL task, which would deadlock against itself.
|
||||
AppEvent closeEvent { .type = APP_EVENT_CLOSE, .timestamp = 0, .result = {} };
|
||||
app_event_emit(ctx->appInstanceId, &closeEvent);
|
||||
}
|
||||
|
||||
// Runs on the wifi service's pubsub thread, not the LVGL task or this app's own thread.
|
||||
void onWifiEvent(Context* ctx, service::wifi::WifiEvent event) {
|
||||
void onWifiEvent(Context* ctx, WifiEvent event) {
|
||||
bool shouldClose = false;
|
||||
|
||||
lvgl_lock();
|
||||
@@ -90,8 +89,6 @@ void onWifiEvent(Context* ctx, service::wifi::WifiEvent event) {
|
||||
lvgl_unlock();
|
||||
|
||||
if (shouldClose) {
|
||||
// Async, non-blocking - same reasoning as onBackPressed() (must not call
|
||||
// app_manager_stop() on ourselves); safe to call from any thread.
|
||||
AppEvent closeEvent { .type = APP_EVENT_CLOSE, .timestamp = 0, .result = {} };
|
||||
app_event_emit(ctx->appInstanceId, &closeEvent);
|
||||
}
|
||||
@@ -121,8 +118,7 @@ void setLoading(Context* ctx, bool loading) {
|
||||
|
||||
void updateView(Context* ctx) {
|
||||
if (ctx->connect_button == nullptr) {
|
||||
// Buried (e.g. this window's own connecting state closed it, or a future dialog opens
|
||||
// on top) - see destroyWidgets().
|
||||
// Buried (e.g. this window's own connecting state closed it, or a future dialog opens on top)
|
||||
return;
|
||||
}
|
||||
if (ctx->connectionError) {
|
||||
@@ -306,46 +302,77 @@ void createWidgets(lv_obj_t* parent, void* userData) {
|
||||
}
|
||||
}
|
||||
|
||||
int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
int32_t appMain(int argc, char* argv[]) {
|
||||
uint32_t appInstanceId = app_scheduler_current_app_id();
|
||||
|
||||
Context ctx {};
|
||||
ctx.appInstanceId = appInstanceId;
|
||||
ctx.initialSsid = (argc > 0) ? argv[0] : std::string();
|
||||
ctx.initialPassword = (argc > 1) ? argv[1] : std::string();
|
||||
|
||||
AppEventSubscription sub {};
|
||||
sub.app_instance_id = appInstanceId;
|
||||
app_event_subscribe(&sub);
|
||||
TaskEventGroup event_group {};
|
||||
task_event_group_construct(&event_group);
|
||||
|
||||
// Subscribed once here, not in createWidgets(): that callback re-runs on every
|
||||
// burial/resurface rebuild, and re-subscribing there would leak the previous subscription
|
||||
// (and its captured ctx pointer) every time, only the last of which shutdown ever cleans up.
|
||||
ctx.wifiSubscription = service::wifi::getPubsub()->subscribe([&ctx](auto event) {
|
||||
onWifiEvent(&ctx, event);
|
||||
});
|
||||
AppEventSubscription sub {};
|
||||
check(app_event_subscribe(&sub, &event_group) == ERROR_NONE);
|
||||
|
||||
Device* wifi_device = nullptr;
|
||||
if (device_get_first_by_type(&WIFI_TYPE, &wifi_device) == ERROR_NONE) {
|
||||
if (wifi_event_subscribe(wifi_device, &ctx.wifiEventSub, &event_group) == ERROR_NONE) {
|
||||
ctx.wifiDevice = wifi_device;
|
||||
} else {
|
||||
LOG_W(TAG, "Failed to subscribe to WiFi events");
|
||||
device_put(wifi_device);
|
||||
}
|
||||
} else {
|
||||
LOG_W(TAG, "No WiFi device found");
|
||||
}
|
||||
|
||||
WindowId window = window_manager_create_ext(appInstanceId, createWidgets, destroyWidgets, &ctx);
|
||||
|
||||
bool shouldClose = false;
|
||||
while (!shouldClose) {
|
||||
AppEvent event {};
|
||||
if (app_event_await(&sub, &event, portMAX_DELAY) != ERROR_NONE) {
|
||||
break;
|
||||
TickType_t wait_timeout = (ctx.wifiDevice == nullptr) ? pdMS_TO_TICKS(500) : portMAX_DELAY;
|
||||
task_event_group_wait_any(&event_group, nullptr, wait_timeout);
|
||||
|
||||
if (ctx.wifiDevice == nullptr) {
|
||||
Device* retry_device = nullptr;
|
||||
if (device_get_first_by_type(&WIFI_TYPE, &retry_device) == ERROR_NONE) {
|
||||
if (wifi_event_subscribe(retry_device, &ctx.wifiEventSub, &event_group) == ERROR_NONE) {
|
||||
ctx.wifiDevice = retry_device;
|
||||
} else {
|
||||
device_put(retry_device);
|
||||
}
|
||||
}
|
||||
}
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
AppEvent event {};
|
||||
while (app_event_poll(&sub, &event) == ERROR_NONE) {
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (shouldClose) break;
|
||||
}
|
||||
|
||||
if (ctx.wifiDevice != nullptr) {
|
||||
WifiEvent wifi_event {};
|
||||
while (wifi_event_poll(&ctx.wifiEventSub, &wifi_event) == ERROR_NONE) {
|
||||
onWifiEvent(&ctx, wifi_event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx.wifiSubscription != nullptr) {
|
||||
service::wifi::getPubsub()->unsubscribe(ctx.wifiSubscription);
|
||||
if (ctx.wifiDevice != nullptr) {
|
||||
wifi_event_unsubscribe(ctx.wifiDevice, &ctx.wifiEventSub);
|
||||
device_put(ctx.wifiDevice);
|
||||
}
|
||||
window_manager_remove(window);
|
||||
app_event_unsubscribe(&sub);
|
||||
check(app_event_unsubscribe(&sub) == ERROR_NONE);
|
||||
task_event_group_destruct(&event_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -7,13 +7,18 @@
|
||||
#include <app/event.h>
|
||||
#include <app/manager.h>
|
||||
#include <app/manifest.h>
|
||||
#include <app/scheduler.h>
|
||||
|
||||
#include <lvgl_window_manager/window_manager.h>
|
||||
|
||||
#include <tactility/check.h>
|
||||
#include <tactility/device.h>
|
||||
#include <tactility/log.h>
|
||||
|
||||
#include <lvgl/lvgl.h>
|
||||
|
||||
#include <atomic>
|
||||
|
||||
namespace tt::app::wifimanage {
|
||||
|
||||
constexpr auto* TAG = "WifiManage";
|
||||
@@ -24,12 +29,18 @@ namespace {
|
||||
|
||||
struct Context {
|
||||
uint32_t appInstanceId;
|
||||
PubSub<service::wifi::WifiEvent>::SubscriptionHandle wifiSubscription = nullptr;
|
||||
// Set once in appMain() before subscribing, left null if this device has no WiFi driver
|
||||
Device* wifiDevice = nullptr;
|
||||
WifiEventSubscription wifiEventSub {};
|
||||
Mutex mutex;
|
||||
Bindings bindings {};
|
||||
State state;
|
||||
View view = View(&bindings, &state);
|
||||
|
||||
TaskEventGroup* eventGroup = nullptr;
|
||||
uint32_t refreshBit = 0;
|
||||
std::atomic<bool> needsRefresh {false};
|
||||
|
||||
void lock() { mutex.lock(); }
|
||||
void unlock() { mutex.unlock(); }
|
||||
};
|
||||
@@ -62,17 +73,18 @@ static void onConnectToHidden() {
|
||||
wificonnect::start();
|
||||
}
|
||||
|
||||
void requestViewUpdate(Context* ctx) {
|
||||
ctx->lock();
|
||||
void updateView(Context* ctx) {
|
||||
// Same lock order as createWidgets() (called with the LVGL lock already held, per the
|
||||
// window-manager's WindowCreateWidgetsFn contract, then acquiring ctx->mutex) - acquiring
|
||||
// these in the opposite order here would deadlock against a concurrent createWidgets() call.
|
||||
lvgl_lock();
|
||||
// Safe even while buried (e.g. WifiApSettings/WifiConnect opened on top): destroyWidgets()
|
||||
// nulls the view's widget pointers before they're deleted, and update() no-ops on that.
|
||||
ctx->lock();
|
||||
ctx->view.update();
|
||||
lvgl_unlock();
|
||||
ctx->unlock();
|
||||
lvgl_unlock();
|
||||
}
|
||||
|
||||
void onWifiEvent(Context* ctx, service::wifi::WifiEvent event) {
|
||||
void onWifiEvent(Context* ctx, WifiEvent event) {
|
||||
auto radio_state = service::wifi::getRadioState();
|
||||
LOG_I(TAG, "Update with state %s", service::wifi::radioStateToString(radio_state));
|
||||
ctx->state.setRadioState(radio_state);
|
||||
@@ -93,7 +105,7 @@ void onWifiEvent(Context* ctx, service::wifi::WifiEvent event) {
|
||||
break;
|
||||
}
|
||||
|
||||
requestViewUpdate(ctx);
|
||||
updateView(ctx);
|
||||
}
|
||||
|
||||
void createWidgets(lv_obj_t* parent, void* userData) {
|
||||
@@ -101,18 +113,18 @@ void createWidgets(lv_obj_t* parent, void* userData) {
|
||||
ctx->lock();
|
||||
ctx->state.setConnectSsid("Connected"); // TODO update with proper SSID
|
||||
ctx->view.init(ctx->appInstanceId, parent);
|
||||
ctx->view.update();
|
||||
ctx->unlock();
|
||||
ctx->needsRefresh = true;
|
||||
task_event_group_signal(ctx->eventGroup, ctx->refreshBit);
|
||||
}
|
||||
|
||||
// Runs with the LVGL lock already held, possibly on another app's thread - see
|
||||
// WindowDestroyWidgetsFn's warnings. Must stay lock-free: View::reset() only nulls pointers.
|
||||
void destroyWidgets(void* userData) {
|
||||
auto* ctx = static_cast<Context*>(userData);
|
||||
ctx->view.reset();
|
||||
}
|
||||
|
||||
int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
int32_t appMain(int argc, char* argv[]) {
|
||||
uint32_t appInstanceId = app_scheduler_current_app_id();
|
||||
Context ctx;
|
||||
ctx.appInstanceId = appInstanceId;
|
||||
ctx.bindings = (Bindings) {
|
||||
@@ -123,18 +135,32 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
.onConnectToHidden = onConnectToHidden
|
||||
};
|
||||
|
||||
ctx.wifiSubscription = service::wifi::getPubsub()->subscribe([&ctx](auto event) {
|
||||
onWifiEvent(&ctx, event);
|
||||
});
|
||||
|
||||
// State update (it has its own locking)
|
||||
ctx.state.setRadioState(service::wifi::getRadioState());
|
||||
ctx.state.setScanning(service::wifi::isScanning());
|
||||
ctx.state.updateApRecords();
|
||||
|
||||
TaskEventGroup event_group {};
|
||||
task_event_group_construct(&event_group);
|
||||
ctx.eventGroup = &event_group;
|
||||
if (task_event_group_claim_bit(&event_group, &ctx.refreshBit) != ERROR_NONE) {
|
||||
LOG_W(TAG, "Failed to claim a refresh bit; resurfacing after burial won't repopulate the view");
|
||||
}
|
||||
|
||||
AppEventSubscription sub {};
|
||||
sub.app_instance_id = appInstanceId;
|
||||
app_event_subscribe(&sub);
|
||||
check(app_event_subscribe(&sub, &event_group) == ERROR_NONE);
|
||||
|
||||
Device* wifi_device = nullptr;
|
||||
if (device_get_first_by_type(&WIFI_TYPE, &wifi_device) == ERROR_NONE) {
|
||||
if (wifi_event_subscribe(wifi_device, &ctx.wifiEventSub, &event_group) == ERROR_NONE) {
|
||||
ctx.wifiDevice = wifi_device;
|
||||
} else {
|
||||
LOG_W(TAG, "Failed to subscribe to WiFi events");
|
||||
device_put(wifi_device);
|
||||
}
|
||||
} else {
|
||||
LOG_W(TAG, "No WiFi device found");
|
||||
}
|
||||
|
||||
WindowId window = window_manager_create_ext(appInstanceId, createWidgets, destroyWidgets, &ctx);
|
||||
|
||||
@@ -154,26 +180,58 @@ int32_t appMain(uint32_t appInstanceId, int argc, char* argv[]) {
|
||||
|
||||
bool shouldClose = false;
|
||||
while (!shouldClose) {
|
||||
AppEvent event {};
|
||||
if (app_event_await(&sub, &event, portMAX_DELAY) != ERROR_NONE) {
|
||||
break;
|
||||
// If the wifi device wasn't started yet when this app opened (boot-order race),
|
||||
// ctx.wifiDevice is still null and there's no wifi-driven wake source to learn
|
||||
// "it's ready now" from, so poll for it on a bounded timeout instead of blocking
|
||||
// indefinitely. Once subscribed, this reverts to
|
||||
// portMAX_DELAY - task_event_group_wait_any() still returns immediately for app_event
|
||||
// and (once live) wifi_event, this timeout only matters while neither has fired yet.
|
||||
TickType_t wait_timeout = (ctx.wifiDevice == nullptr) ? pdMS_TO_TICKS(500) : portMAX_DELAY;
|
||||
task_event_group_wait_any(&event_group, nullptr, wait_timeout);
|
||||
|
||||
if (ctx.wifiDevice == nullptr) {
|
||||
Device* retry_device = nullptr;
|
||||
if (device_get_first_by_type(&WIFI_TYPE, &retry_device) == ERROR_NONE) {
|
||||
if (wifi_event_subscribe(retry_device, &ctx.wifiEventSub, &event_group) == ERROR_NONE) {
|
||||
ctx.wifiDevice = retry_device;
|
||||
} else {
|
||||
device_put(retry_device);
|
||||
}
|
||||
}
|
||||
}
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
AppEvent event {};
|
||||
while (app_event_poll(&sub, &event) == ERROR_NONE) {
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (shouldClose) break;
|
||||
}
|
||||
|
||||
if (ctx.wifiDevice != nullptr) {
|
||||
WifiEvent wifi_event {};
|
||||
while (wifi_event_poll(&ctx.wifiEventSub, &wifi_event) == ERROR_NONE) {
|
||||
onWifiEvent(&ctx, wifi_event);
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx.needsRefresh.exchange(false)) {
|
||||
updateView(&ctx);
|
||||
}
|
||||
}
|
||||
|
||||
ctx.lock();
|
||||
service::wifi::getPubsub()->unsubscribe(ctx.wifiSubscription);
|
||||
ctx.wifiSubscription = nullptr;
|
||||
ctx.unlock();
|
||||
if (ctx.wifiDevice != nullptr) {
|
||||
wifi_event_unsubscribe(ctx.wifiDevice, &ctx.wifiEventSub);
|
||||
device_put(ctx.wifiDevice);
|
||||
}
|
||||
|
||||
window_manager_remove(window);
|
||||
app_event_unsubscribe(&sub);
|
||||
check(app_event_unsubscribe(&sub) == ERROR_NONE);
|
||||
task_event_group_destruct(&event_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user