#pragma once // ui-lvgl: the rich (colour + touch) frontend of the UI Core. Wio Tracker L2 // first. All application state lives in the Core (../ui-core); this class owns // only LVGL screens, display power and input. See docs/development/ui-core.md. #include #include #include #include #include #include #ifdef PIN_BUZZER #include #endif #include "../AbstractUITask.h" #include "../NodePrefs.h" #include "../ui-core/UiCoreHost.h" class UiCore; class NearbyModel; struct UiEvent; class UITask : public UITaskBase, public UiCoreHost { public: UITask(mesh::MainBoard* board, BaseSerialInterface* serial) : UITaskBase(board, serial) {} void begin(DisplayDriver* display, SensorManager* sensors, NodePrefs* node_prefs); void loop() override; void notify(UIEventType t = UIEventType::none) override; void shutdown(bool restart = false) override; MyMesh::Listener* meshListener() override; // UiCoreHost bool isViewingChannel(uint8_t channel_idx) override; bool isViewingDM(const uint8_t* pub_key) override; void onViewedHistoryGrew(bool channel) override { (void)channel; _thread_dirty = true; } void botSetGPS(bool on) override; void applySoundPrefs() override; // ── Navigation (called from LVGL event callbacks) ──────────────────────── void showHome(); void setHomePage(int page); void showChats(); void showContacts(); void showSettings(); void showSchemaSettings(int page); void pruneContacts(); void setBrightnessPct(uint8_t pct, bool save); void applyDisplayPrefs() override; void setSchemaValue(int idx, int v); void showNearby(); void showMap(); // in its current mode void openMap(bool nav); // Nodes map (false) or Navigation map (true) void mapLongPress(int x, int y); void mapZoom(int delta); void mapCenterOnMe(); void mapPan(int dx, int dy); void mapOpenMarker(int idx); void mapDownloadPopup(); void mapDownloadClose(); void mapDownloadStart(); void mapDownloadStop(); void mapDownloadResume(); void mapDownloadDiscard(); void mapDownloadZmax(int delta); // Navigation map (NavMap.h) void navTargetsPopup(); void navClosePopup(); void navPick(int code); void navWaypointMenu(int idx); void navWaypointAction(uint8_t act); void navRenameDone(bool ok); void navMarkHere(); void navAveragingCancel(); void navToNode(const uint8_t* key, int32_t lat, int32_t lon, const char* name); void navToolsPopup(); void navToolAction(uint8_t act); void navSetShareTarget(int sel); void navWaypointsPopup(); void navCoordsPopup(); void navCoordsDone(bool ok); void shareToMessage(const char* text); void messageLocationAction(int idx, bool save); void showWifi(bool from_map); void wifiSetAllowed(bool on); void wifiScan(); void wifiPick(int idx); void wifiSave(); void wifiEdit(lv_obj_t* ta); void wifiKeyboardHide(); void setNearbyFilter(uint8_t f); void toggleNearbySort(); void startNearbyScan(); void closeScanPopup(); void openScanNode(int row); void openNode(int row); void nodeAction(uint8_t action); void setKeyboardAlphabets(int main_idx, int alt_sel); void openChannel(uint8_t channel_idx); void openDM(const uint8_t* pub_key); void back(); void sendFromCompose(); void setKeyboardVisible(bool show); void showToast(const char* text, uint32_t ms = 2500); // Clock tools (ClockScreen.h) void showClock(); void clockTab(int tab); void clockAction(uint8_t act); void setAlarm(int which, int v); void dismissRing(); // Sound (SoundScreen.h): the speaker, Settings > Sound, the melody editor void playMelody(const char* melody); // through mute (alarms, previews) void stopMelody(); bool melodyPlaying(); int melodyNote(); // the note sounding now, -1 silent void setSoundMode(int mode); void setSoundVolume(int level); void showMelodies(int slot); void melodySlot(int slot); void melodyPick(int idx); void melodySet(uint8_t which, int v); void melodyAction(uint8_t act); void conversationMelody(int v); void hearMelody(int slot); #ifdef PIN_BUZZER // For the sim page's Web Audio speaker (sim_buzzer_* in UITask.cpp). bool isBuzzerPlaying() { return _buzzer.isPlaying(); } uint16_t buzzerFreqHz() const; uint8_t buzzerVolume() const { return _buzzer.getVolume(); } #endif // Quick messages, placeholders, advert, Bluetooth (QuickScreen.h) void quickPopup(); // the compose bar's "+" void quickSend(int slot); void quickInsert(int ph); void showQuickMsgs(); void quickEdit(int slot); void quickEditDone(bool ok); void quickEditInsert(int ph); void advertPopup(); void advertSend(bool flood); void setBluetooth(bool on); void markAllRead(); // Settings > Radio (RadioScreen.h) void showRadio(); void radioSet(int which, int v); void radioFreqPopup(bool repeater); // the companion's frequency, or the repeater profile's void radioFreqDone(bool ok); // Settings > Radio: my presets, scopes (RadioExtras.h) void presetMenu(int slot); void presetAction(uint8_t act); void radioNamePopup(uint8_t what); void radioNameDone(bool ok); void showScopes(); void scopeMenu(int idx); void scopeAction(uint8_t act); // Settings > Repeater (RepeaterScreen.h) void showRepeater(); void repeaterSet(int which, int v); void repeaterScopesPopup(); void repeaterScopeSet(uint8_t i, bool on); // Channels (ChannelScreen.h) void channelMenu(int idx); void channelSet(uint8_t which, int v); void channelAction(uint8_t act); void showChannelEdit(int idx); void channelEditType(int type); void channelEditHex(bool hex); void channelEditField(lv_obj_t* ta); void channelEditKbHide(); void channelEditSave(); // Remote admin (AdminScreen.h) void openAdmin(const uint8_t* pub_key); void adminTab(int tab); void adminRow(int row); void adminValue(uint8_t act); void adminChoice(int idx); void adminLogin(bool ok); void adminTextDone(bool ok); void adminCancelWait(); // Bot settings (BotScreen.h) void showBot(); void botTab(int tab); void botRow(int row); void botToggle(int row, bool on); void botPick(int idx); void botHour(uint8_t act); void botTextDone(bool ok); // ConversationScreen.h void openRoom(const uint8_t* pub_key); void roomLoginPopup(const uint8_t* pub_key); void roomLoginDone(bool ok); void conversationMenu(const uint8_t* pub_key); // nullptr: the open thread's void conversationAction(uint8_t act); void conversationNotif(int v); void messageMenu(int idx); void messageAction(uint8_t act); void toggleChatFilter(uint8_t which); // DeviceScreen.h void nodeNamePopup(); void nodeNameDone(bool ok); void powerPopup(bool restart); void unlockScreen(); bool locked() const; void showFavourites(); void showDiag(); void diagTab(int tab); void diagResetPopup(); void diagReset(); void showCompass(); void favTap(int slot); void favHold(int slot); void favAction(uint8_t act); void favPick(int code); void pinPopup(bool channel, uint8_t ch_idx, const uint8_t* pub_key); void pinTo(int slot); void setGps(bool on); bool ensureGps(); // true with a fix; else turns GPS on / says it's waiting // Kept for main.cpp's sim hooks (ui-new API). void openContactDM(const ContactInfo& ci) { openDM(ci.id.pub_key); } void openAdminFor(const ContactInfo& ci, bool from_picker) { (void)ci; (void)from_picker; } private: enum Screen : uint8_t { SCR_HOME, SCR_CHATS, SCR_CONTACTS, SCR_THREAD, SCR_SETTINGS, SCR_NEARBY, SCR_NODE, SCR_MAP, SCR_WIFI, SCR_SETTINGS_NAV, SCR_CLOCK, SCR_RADIO, SCR_CHANNEL_EDIT, SCR_ADMIN, SCR_BOT, SCR_FAVS, SCR_DIAG, SCR_COMPASS, SCR_SCOPES, SCR_REPEATER, SCR_MELODY, SCR_QUICK }; void buildStatusBar(); void refreshStatusBar(); lv_obj_t* newScreen(const char* title, bool with_back); void buildHome(); void refreshHome(); void homeSwipePoll(); void buildChats(); void buildContacts(); void buildSettings(); void buildSchemaSettings(); void buildNearby(); void refreshNearbyList(); uint32_t nearbySignature() const; void showScanPopup(); void refreshScanPopup(); void buildMap(); void layoutMap(); void mapLoop(); void rebuildMapMarkers(); void rebuildNodeMarkers(); void addMapMark(uint8_t kind, int idx, int32_t lat_e6, int32_t lon_e6, uint32_t col, const char* text); void mapPointToLatLon(int x, int y, int32_t& lat_e6, int32_t& lon_e6) const; double mapCenterBias() const; void buildNavLayers(); void buildNavControls(lv_obj_t* body); void rebuildNavMarkers(); void layoutNav(); void refreshNavBar(); void navFrameTarget(); void navSetTarget(uint8_t kind, const uint8_t* key, int32_t lat, int32_t lon, const char* name); lv_obj_t* navPopupPanel(const char* title, bool full); void navRenamePopup(int idx); void navAddWaypoint(int32_t lat, int32_t lon); void navDropAt(int x, int y); void navSpotPopup(int32_t lat, int32_t lon); void refreshNavTools(); void navPollAveraging(); void navPollTrackBack(); bool navCurrentTarget(int32_t& lat, int32_t& lon, char* name, int n, bool& person, bool& set); bool exportTrailGpx(char* name_out, size_t n); void mapDownloadTick(); void refreshDownloadPopup(); void buildWifi(); void pollWifiScan(); void buildNode(); void refreshNode(); void buildThread(); void refreshThread(); uint32_t threadSignature() const; void buildClock(); void buildRadio(); void rebuildRadio(); void buildRadioExtras(lv_obj_t* body); void buildScopes(); void buildRepeater(); void rebuildRepeater(); void buildSoundRows(lv_obj_t* body, bool top); void buildMelodies(); void buildQuickMsgs(); bool sendThreadText(const char* text); void refreshMelody(); void melodySave(); void radioCloseFreq(); void buildChannelEdit(); void buildAdmin(); void buildBot(); void refreshAdminStatus(); void adminLeave(); void adminPoll(); void roomPoll(); void lockScreen(); void refreshLock(); void lockPoll(); void buildFavourites(); void buildDiag(); void refreshDiag(); void buildCompass(); void refreshCompass(); void favPickPopup(int slot); void adminValuePopup(); void adminTextPopup(const char* text, bool digits); void adminReplyPopup(const char* text); bool radioPopupOpen() const; void refreshClock(); void showRing(const char* text); void hideRing(); void drainCoreEvents(); void onMessageArrived(const UiEvent& ev); void wake(); void sleep(); void toggleMute(); uint32_t _next_wake_poll_ms = 0; bool _wake_down = false; uint32_t autoOffMillis() const; void checkLowBattery(); #ifdef PIN_BUZZER genericBuzzer _buzzer; char _notif_mel_buf[220]; // a user melody's RTTTL while it plays (the player copies it) #endif // Who the message being notified came from (SoundNotifier's overrides). bool _notif_dm_valid = false; uint8_t _notif_dm_prefix[4] = {0}; int _notif_ch_idx = -1; DisplayDriver* _display = nullptr; SensorManager* _sensors = nullptr; NodePrefs* _prefs = nullptr; UiCore* _core = nullptr; Screen _screen = SCR_HOME; bool _asleep = false; uint32_t _next_status_ms = 0; uint32_t _next_thread_check_ms = 0; uint32_t _next_trackback_ms = 0; uint32_t _next_clock_ms = 0; uint8_t _settings_page = 0; // settings::Page shown in SCR_SETTINGS_NAV uint32_t _prune_armed_ms = 0; uint16_t _batt_mv = 0; // smoothed, for the low-battery shutdown uint32_t _next_batt_ms = 0; lv_obj_t* _prune_lbl = nullptr; // Open conversation (SCR_THREAD) bool _thread_is_channel = false; uint8_t _thread_channel = 0; uint8_t _thread_key[PUB_KEY_SIZE] = {0}; bool _thread_dirty = false; uint32_t _thread_sig = 0; // Widgets lv_obj_t* _status_time = nullptr; lv_obj_t* _status_icons = nullptr; lv_obj_t* _status_gps = nullptr; lv_obj_t* _toast = nullptr; lv_timer_t* _toast_timer = nullptr; lv_obj_t* _home_clock = nullptr; lv_obj_t* _home_date = nullptr; lv_obj_t* _home_unread = nullptr; lv_obj_t* _header = nullptr; // current screen's title bar (nullptr on Home) lv_obj_t* _body = nullptr; lv_obj_t* _thread_list = nullptr; lv_obj_t* _compose_ta = nullptr; lv_obj_t* _keyboard = nullptr; // Nearby (SCR_NEARBY) / node detail (SCR_NODE); list data in NearbyModel NearbyModel* _nearby = nullptr; NearbyModel* _scan = nullptr; // NODE_DISCOVER results: nodes in range now (popup over the list) bool _scanning = false; bool _node_from_scan = false; uint32_t _scan_sig = 0; lv_obj_t* _scan_overlay = nullptr; lv_obj_t* _scan_list = nullptr; lv_obj_t* _scan_status = nullptr; uint32_t _scan_until_ms = 0; uint32_t _nearby_sig = 0; uint32_t _next_nearby_ms = 0; bool _pinging = false; uint32_t _ping_started_ms = 0; uint32_t _delete_armed_ms = 0; lv_obj_t* _nearby_list = nullptr; lv_obj_t* _nearby_status = nullptr; lv_obj_t* _nearby_sort_lbl = nullptr; lv_obj_t* _nearby_chips = nullptr; lv_obj_t* _node_info = nullptr; lv_obj_t* _node_ping = nullptr; lv_obj_t* _node_delete_lbl = nullptr; bool _node_from_map = false; // Map (SCR_MAP): view centre in fractional tile coords at zoom _map_z double _map_cx = 0, _map_cy = 0; int _map_z = 0; // 0 = not initialised yet bool _map_follow = true; // keep centred on own position until panned bool _map_pending = false; // visible tiles still to decode uint32_t _next_map_marks_ms = 0; lv_obj_t* _map_area = nullptr; lv_obj_t* _map_tiles[6] = {nullptr}; lv_obj_t* _map_marks = nullptr; lv_obj_t* _map_me = nullptr; lv_obj_t* _map_zoom_lbl = nullptr; lv_obj_t* _map_hint = nullptr; lv_obj_t* _map_dl_pill = nullptr; // download progress over the map lv_obj_t* _dl_overlay = nullptr; // download popup lv_obj_t* _dl_info = nullptr; lv_obj_t* _dl_zoom_lbl = nullptr; lv_obj_t* _dl_start_lbl = nullptr; lv_obj_t* _dl_job_row = nullptr; // "Unfinished ... Resume" in the popup lv_obj_t* _dl_job_lbl = nullptr; int _dl_zmax = 0; uint8_t _dl_last_state = 0; // Navigation map (SCR_MAP with _map_nav) bool _map_nav = false; uint32_t _next_nav_bar_ms = 0; lv_obj_t* _nav_bar = nullptr; // target bar along the bottom lv_obj_t* _nav_title = nullptr; lv_obj_t* _nav_info = nullptr; lv_obj_t* _nav_clear = nullptr; lv_obj_t* _nav_overlay = nullptr; // target list / waypoint menu / rename lv_obj_t* _nav_ta = nullptr; lv_obj_t* _nav_kb = nullptr; lv_obj_t* _nav_del_lbl = nullptr; uint32_t _nav_del_armed_ms = 0; int _nav_wp = -1; // waypoint the menu / rename is about lv_obj_t* _nav_rec = nullptr; // "REC 1.2 km LIVE 58m" pill lv_obj_t* _nav_avg_pill = nullptr; // GPS averaging progress (tap: cancel) lv_obj_t* _nav_trail_lbl = nullptr; // tools panel lv_obj_t* _nav_trail_btn = nullptr; lv_obj_t* _nav_reset_lbl = nullptr; lv_obj_t* _nav_share_lbl = nullptr; lv_obj_t* _nav_share_btn = nullptr; lv_obj_t* _nav_tb_btn = nullptr; uint32_t _nav_reset_armed_ms = 0; int32_t _nav_spot_lat = 0, _nav_spot_lon = 0; // the spot a long-press picked char _share_text[96] = ""; // waiting for a conversation to be picked (shareToMessage) // WiFi settings (SCR_WIFI) bool _wifi_from_map = false; bool _wifi_scanning = false; lv_obj_t* _wifi_ssid = nullptr; lv_obj_t* _wifi_pass = nullptr; lv_obj_t* _wifi_kb = nullptr; lv_obj_t* _wifi_list = nullptr; lv_obj_t* _wifi_status = nullptr; };