| 24 | extern const AppManifest manifest; |
| 25 | |
| 26 | class DevelopmentApp final : public App { |
| 27 | |
| 28 | lv_obj_t* enableSwitch = nullptr; |
| 29 | lv_obj_t* enableOnBootSwitch = nullptr; |
| 30 | lv_obj_t* statusLabel = nullptr; |
| 31 | std::shared_ptr<service::development::DevelopmentService> service; |
| 32 | |
| 33 | Timer timer = Timer(Timer::Type::Periodic, pdMS_TO_TICKS(1000), [this] { |
| 34 | auto lock = lvgl::getSyncLock()->asScopedLock(); |
| 35 | // TODO: There's a crash when this is called when the app is being destroyed |
| 36 | if (lock.lock(lvgl::defaultLockTime) && lvgl::isStarted()) { |
| 37 | updateViewState(); |
| 38 | } |
| 39 | }); |
| 40 | |
| 41 | static void onEnableSwitchChanged(lv_event_t* event) { |
| 42 | lv_event_code_t code = lv_event_get_code(event); |
| 43 | auto* widget = static_cast<lv_obj_t*>(lv_event_get_target(event)); |
| 44 | if (code == LV_EVENT_VALUE_CHANGED) { |
| 45 | bool is_on = lv_obj_has_state(widget, LV_STATE_CHECKED); |
| 46 | auto* app = static_cast<DevelopmentApp*>(lv_event_get_user_data(event)); |
| 47 | bool is_changed = is_on != app->service->isEnabled(); |
| 48 | if (is_changed) { |
| 49 | app->service->setEnabled(is_on); |
| 50 | } |
| 51 | } |
| 52 | } |
| 53 | |
| 54 | static void onEnableOnBootSwitchChanged(lv_event_t* event) { |
| 55 | lv_event_code_t code = lv_event_get_code(event); |
| 56 | auto* widget = static_cast<lv_obj_t*>(lv_event_get_target(event)); |
| 57 | if (code == LV_EVENT_VALUE_CHANGED) { |
| 58 | bool is_on = lv_obj_has_state(widget, LV_STATE_CHECKED); |
| 59 | bool is_changed = is_on != service::development::shouldEnableOnBoot(); |
| 60 | if (is_changed) { |
| 61 | // Dispatch it, so file IO doesn't block the UI |
| 62 | getMainDispatcher().dispatch([is_on] { |
| 63 | service::development::setEnableOnBoot(is_on); |
| 64 | }); |
| 65 | } |
| 66 | } |
| 67 | } |
| 68 | |
| 69 | void updateViewState() { |
| 70 | if (!service->isEnabled()) { |
| 71 | lv_label_set_text(statusLabel, "Service disabled"); |
| 72 | } else if (service::wifi::getRadioState() != service::wifi::RadioState::ConnectionActive) { |
| 73 | lv_label_set_text(statusLabel, "Waiting for connection..."); |
| 74 | } else { // enabled and connected to wifi |
| 75 | auto ip = service::wifi::getIp(); |
| 76 | if (ip.empty()) { |
| 77 | lv_label_set_text(statusLabel, "Waiting for IP..."); |
| 78 | } else { |
| 79 | const std::string status = std::format("Available at {}", ip); |
| 80 | lv_label_set_text(statusLabel, status.c_str()); |
| 81 | } |
| 82 | } |
| 83 | } |
nothing calls this directly
no test coverage detected