mirror of
https://github.com/ALLFATHER-BV/wadamesh.git
synced 2026-10-15 12:39:59 +00:00
feat(ui): lock screen shows the battery, laid out for every panel; P4 BOOT button locks
Lock screen (all boards, #579): the default view is now drawn from parts instead of the old 320x240 bitmap with the padlock and wordmark baked in, which cover-scaled into a jumble on any other panel shape. WADAMESH sits at the top, the clock below it (clear of the status bar), a smaller padlock in the centre with the unread count to its left and a new battery readout to its right, each centred between the padlock and the screen edge. Short panels get a smaller wordmark and padlock. The clock's burn-in drift now moves around its new place instead of snapping it back to y=30 every minute. T-Deck Pro keeps its black-on-white e-paper colours; custom wallpapers are unchanged. T-Display P4: the BOOT button (GPIO35) now works like the Wio Tracker L2's wake button -- a press wakes or lights the lock screen, a 2 s hold locks or unlocks -- so the P4 gets the lock screen and the "Lock when screen off" setting. It gets no Power-off row: GPIO35 cannot wake the P4 from deep sleep. Also: the chat list's per-row gear clears the list scrollbar on large panels. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
ad91b1cb3f
commit
b078df52e9
+4
-1
@@ -81,7 +81,10 @@ USB) and the [GitHub releases](https://github.com/ALLFATHER-BV/wadamesh/releases
|
||||
validated at boot; if it reports lost integrity, the same optional saved-Wi-Fi
|
||||
cold-boot sync offered on T-Deck is available in Clock settings. New in beta_38;
|
||||
report anything that feels off.
|
||||
- **T-Display P4**: touch UI with the on-screen keyboard. The optional clip-on
|
||||
- **T-Display P4**: touch UI with the on-screen keyboard. The BOOT button wakes
|
||||
the screen (or lights the lock screen) and holding it for two seconds locks or
|
||||
unlocks, as the Wio Tracker L2's wake button does; "Lock when screen off" is
|
||||
under Settings, Lock screen. The optional clip-on
|
||||
keyboard expansion can be attached or removed while running and is picked up
|
||||
within a couple of seconds; while it is on, it types into the focused field
|
||||
and the on-screen keyboard stays down (tap the field again to bring it up).
|
||||
|
||||
+198
-131
@@ -49,14 +49,6 @@ static void* wadaMp3Scratch() { return s_wada_mp3_scratch; }
|
||||
#include <esp_sleep.h> // esp_deep_sleep_start / ext0 wakeup for the power-off menu
|
||||
#include <driver/rtc_io.h> // rtc_gpio_pullup_en — hold the wake pin's level in deep sleep
|
||||
#include "assets/lockscreen_placeholder_jpg.h" // seeded to SPIFFS /lock/placeholder.jpg on first boot (PNG decode is broken on this board)
|
||||
#if CAP_LOCK_SCREEN
|
||||
#if !defined(HAS_TDECK_PRO)
|
||||
#include "assets/lockscreen_wallpaper_rgb565.h" // crisp pre-dithered default lock-screen wallpaper (no JPEG banding)
|
||||
#endif
|
||||
#if defined(TLORA_PAGER)
|
||||
#include "assets/lockscreen_wallpaper_pager_rgb565.h" // native 480x222 crop/layout for this board's wide/short panel
|
||||
#endif
|
||||
#endif
|
||||
#include <esp_timer.h>
|
||||
#include <esp_chip_info.h>
|
||||
#include <nvs.h> // nvs_get_stats() for the About-tab NVS usage line
|
||||
@@ -14039,6 +14031,8 @@ static void lockOnScreenOffToggleCb(lv_event_t* e) {
|
||||
const char* unlock_hint = on ? TR("Locks when screen off\n(double-press d-pad center to unlock)") : TR("Screen-off just dims");
|
||||
#elif defined(HAS_WIO_TRACKER_L2)
|
||||
const char* unlock_hint = on ? TR("Locks when screen off\n(hold the wake button to unlock)") : TR("Screen-off just dims");
|
||||
#elif defined(HAS_TDISPLAY_P4)
|
||||
const char* unlock_hint = on ? TR("Locks when screen off\n(hold the BOOT button to unlock)") : TR("Screen-off just dims");
|
||||
#elif defined(HAS_TANMATSU)
|
||||
const char* unlock_hint = on ? TR("Locks when screen off\n(press Volume Down to unlock)") : TR("Screen-off just dims");
|
||||
#elif defined(TLORA_PAGER)
|
||||
@@ -16126,10 +16120,8 @@ static void buildDeviceSettings(int sec) {
|
||||
#endif // HAS_TDECK_GT911 || HAS_THINKNODE_M9
|
||||
|
||||
// Auto-lock on screen-off: when the idle timeout dims the screen, also hard-lock so the
|
||||
// touchscreen is inert (Tim: pocket-taps while dark). NOT on the P4 — it has no unlock path
|
||||
// (no button/trackball and no touch-unlock overlay yet), so a hard lock there is a power-cycle
|
||||
// trap. The P4 still dims on idle (screen-off wakes on touch); a proper P4 lock is a follow-up.
|
||||
#if !defined(HAS_TDISPLAY_P4)
|
||||
// touchscreen is inert (Tim: pocket-taps while dark). Every board here has a deliberate
|
||||
// unlock control; the P4's is holding its BOOT button.
|
||||
{
|
||||
int h = settingsRowLabel(body, y, 6, TR("Lock when screen off"), COLOR_SUB, nullptr, 56);
|
||||
lv_obj_t* sw = lv_switch_create(body);
|
||||
@@ -16147,7 +16139,6 @@ static void buildDeviceSettings(int sec) {
|
||||
#endif
|
||||
y += LV_MAX(40, h + 12);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
@@ -41385,6 +41376,22 @@ static void formatChatRowTime(char* buf, size_t cap, uint32_t ts) {
|
||||
else strftime(buf, cap, "%d/%m/%y", &tmv);
|
||||
}
|
||||
|
||||
// How far in from the row's right edge the per-row settings gear sits. On the
|
||||
// large panels the list's scrollbar is drawn over that edge and covered the
|
||||
// gear, so clear it: the scrollbar's own width and edge gap, plus a margin.
|
||||
static lv_coord_t threadGearRightInset(lv_obj_t* row) {
|
||||
#if CAP_LARGE_SCREEN
|
||||
for (lv_obj_t* o = row ? lv_obj_get_parent(row) : nullptr; o; o = lv_obj_get_parent(o)) {
|
||||
if (!lv_obj_has_flag(o, LV_OBJ_FLAG_SCROLLABLE)) continue;
|
||||
return lv_obj_get_style_width(o, LV_PART_SCROLLBAR) +
|
||||
lv_obj_get_style_pad_right(o, LV_PART_SCROLLBAR) + 6;
|
||||
}
|
||||
#else
|
||||
(void)row;
|
||||
#endif
|
||||
return 2;
|
||||
}
|
||||
|
||||
static void refreshChatList(LvChatPanel& p) {
|
||||
if (!g_lv.task || !p.list_cont) return;
|
||||
|
||||
@@ -41481,13 +41488,14 @@ static void refreshChatList(LvChatPanel& p) {
|
||||
// Per-row settings gear on the far right — opens the thread-settings sheet (same as a long-press
|
||||
// and the in-chat cog). Tapping it swallows the gesture so the row's CLICKED can't open the chat.
|
||||
const lv_coord_t gear_w = 28;
|
||||
const lv_coord_t gear_r = threadGearRightInset(btn);
|
||||
{
|
||||
lv_obj_t* gear = lv_btn_create(btn);
|
||||
lv_obj_remove_style_all(gear);
|
||||
lv_obj_add_flag(gear, LV_OBJ_FLAG_IGNORE_LAYOUT);
|
||||
lv_obj_add_flag(gear, NAV_HMOVE_FLAG); // keyboard nav: reach the gear with RIGHT (not UP/DOWN); keeps the row itself focusable so the chat opens
|
||||
lv_obj_set_size(gear, gear_w, 30);
|
||||
lv_obj_align(gear, LV_ALIGN_RIGHT_MID, -2, 0);
|
||||
lv_obj_align(gear, LV_ALIGN_RIGHT_MID, -gear_r, 0);
|
||||
lv_obj_add_event_cb(gear, threadGearCb, LV_EVENT_CLICKED, &p.ctx_store[i]);
|
||||
lv_obj_t* gl = lv_label_create(gear);
|
||||
lv_label_set_text(gl, LV_SYMBOL_SETTINGS);
|
||||
@@ -41496,7 +41504,7 @@ static void refreshChatList(LvChatPanel& p) {
|
||||
lv_obj_center(gl);
|
||||
}
|
||||
// Last-message time, just left of the gear; the unread badge + @ sit to its left.
|
||||
const lv_coord_t time_x = (lv_coord_t)(-(10 + gear_w));
|
||||
const lv_coord_t time_x = (lv_coord_t)(-(8 + gear_r + gear_w));
|
||||
char tbuf[16];
|
||||
formatChatRowTime(tbuf, sizeof(tbuf), ts);
|
||||
lv_coord_t time_w = 0;
|
||||
@@ -41652,13 +41660,14 @@ static void refreshChatList(LvChatPanel& p) {
|
||||
|
||||
// Per-row settings gear on the far right (same behaviour as the compact rows).
|
||||
const lv_coord_t gear_w = 28;
|
||||
const lv_coord_t gear_r = threadGearRightInset(btn);
|
||||
{
|
||||
lv_obj_t* gear = lv_btn_create(btn);
|
||||
lv_obj_remove_style_all(gear);
|
||||
lv_obj_add_flag(gear, LV_OBJ_FLAG_IGNORE_LAYOUT);
|
||||
lv_obj_add_flag(gear, NAV_HMOVE_FLAG);
|
||||
lv_obj_set_size(gear, gear_w, kThreadRowH - 8);
|
||||
lv_obj_align(gear, LV_ALIGN_RIGHT_MID, -2, 0);
|
||||
lv_obj_align(gear, LV_ALIGN_RIGHT_MID, -gear_r, 0);
|
||||
lv_obj_add_event_cb(gear, threadGearCb, LV_EVENT_CLICKED, &p.ctx_store[i]);
|
||||
lv_obj_t* gl = lv_label_create(gear);
|
||||
lv_label_set_text(gl, LV_SYMBOL_SETTINGS);
|
||||
@@ -41668,7 +41677,7 @@ static void refreshChatList(LvChatPanel& p) {
|
||||
}
|
||||
|
||||
// Time, top-right (left of the gear).
|
||||
const lv_coord_t time_x = (lv_coord_t)(-(10 + gear_w));
|
||||
const lv_coord_t time_x = (lv_coord_t)(-(8 + gear_r + gear_w));
|
||||
char tbuf[16];
|
||||
formatChatRowTime(tbuf, sizeof(tbuf), ts);
|
||||
lv_coord_t time_w = 0;
|
||||
@@ -43491,10 +43500,9 @@ static unsigned long s_lock_unread_ms = 0; // 1 Hz poll limiter
|
||||
#if defined(HAS_TDECK_PRO)
|
||||
static bool s_lock_epaper_default = false; // built-in white lock view vs custom wallpaper
|
||||
#endif
|
||||
#if defined(TLORA_PAGER)
|
||||
static lv_obj_t* s_lock_status = nullptr; // "Screen locked" -- tracked for lockscreenHide() cleanup
|
||||
static lv_obj_t* s_lock_hint = nullptr; // unlock hint -- tracked for lockscreenHide() cleanup
|
||||
#endif
|
||||
static lv_coord_t s_lock_clock_y = 30; // the clock's place (lockscreenShow); the drift moves around it
|
||||
static lv_obj_t* s_lock_batt = nullptr; // battery glyph + % to the right of the padlock
|
||||
static int s_lock_batt_key = -1; // last level drawn (redraw guard; 1000 = charging)
|
||||
|
||||
// How long the trackball must be held to unlock, in ms.
|
||||
static const unsigned long kLockUnlockHoldMs = 1000;
|
||||
@@ -43574,20 +43582,9 @@ static void lockscreenUpdateClock() {
|
||||
// the panel. Deterministic from the minute, so it also moves on every reveal.
|
||||
const int dx = (mm % 5) * 3 - 6; // -6 … +6 px
|
||||
const int dy = ((mm / 5) % 3) * 4 - 4; // -4 … +4 px
|
||||
#if defined(TLORA_PAGER)
|
||||
// Same anti-burn-in drift, but around this board's top-LEFT clock position
|
||||
// (lockscreenShow()'s TOP_LEFT/6,30) instead of T-Deck's TOP_MID -- without
|
||||
// this override every periodic clock update (this function runs on every
|
||||
// minute rollover) silently snapped the clock back to horizontally
|
||||
// centered, undoing the top-left placement the moment it first ticked.
|
||||
// The unread badge stays in its own right-column spot (300,70) -- it
|
||||
// doesn't ride with the clock on this layout, so no drift needed there.
|
||||
lv_obj_align(s_lock_clock, LV_ALIGN_TOP_LEFT, 6 + dx, 30 + dy);
|
||||
#else
|
||||
lv_obj_align(s_lock_clock, LV_ALIGN_TOP_MID, dx, 30 + dy);
|
||||
// The unread badge rides along with the same drift so it never parks either.
|
||||
if (s_lock_unread) lv_obj_align(s_lock_unread, LV_ALIGN_TOP_MID, dx, 68 + dy);
|
||||
#endif
|
||||
// Around the place lockscreenShow() gave it: re-aligning to a fixed y here
|
||||
// would put it back under the status bar / wordmark on the first tick.
|
||||
lv_obj_align(s_lock_clock, LV_ALIGN_TOP_MID, dx, s_lock_clock_y + dy);
|
||||
s_lock_clock_min = mm;
|
||||
}
|
||||
|
||||
@@ -43605,6 +43602,22 @@ static void lockscreenUpdateUnread() {
|
||||
lv_obj_clear_flag(s_lock_unread, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
|
||||
// The battery readout beside the padlock: the status bar's glyph, plus the
|
||||
// percentage unless charging (the bolt says it then, as in the status bar).
|
||||
static void lockscreenUpdateBattery() {
|
||||
if (!s_lock_batt) return;
|
||||
const uint16_t mv = batteryMvSmoothed();
|
||||
const bool charging = batteryIsCharging(mv);
|
||||
const int pct = batteryPercentFromMv(mv);
|
||||
const int key = charging ? 1000 : pct;
|
||||
if (key == s_lock_batt_key) return;
|
||||
s_lock_batt_key = key;
|
||||
char b[24];
|
||||
if (charging || pct < 0) snprintf(b, sizeof b, "%s", batteryGlyphForMv(mv));
|
||||
else snprintf(b, sizeof b, "%s %d%%", batteryGlyphForMv(mv), pct);
|
||||
lv_label_set_text(s_lock_batt, b);
|
||||
}
|
||||
|
||||
static void lockscreenUnlockPopupHide() {
|
||||
if (s_unlock_popup) { lv_obj_del(s_unlock_popup); s_unlock_popup = nullptr; s_unlock_count = nullptr; }
|
||||
}
|
||||
@@ -43660,8 +43673,13 @@ static void lockscreenShow() {
|
||||
const lv_coord_t sh = lv_disp_get_ver_res(nullptr);
|
||||
char wpath[TOUCH_LOCK_WALLPAPER_MAXLEN];
|
||||
touchPrefsGetLockWallpaper(wpath, sizeof wpath);
|
||||
// The default view is drawn from parts -- wordmark, clock, padlock -- rather
|
||||
// than the old 320x240 bitmap with the padlock and wordmark baked in. Cover-
|
||||
// scaled onto any other panel shape, that bitmap cropped the wordmark and
|
||||
// zoomed everything into one jumble in the middle, under the clock.
|
||||
const bool native = !strcmp(wpath, "/lock/placeholder.jpg");
|
||||
#if defined(HAS_TDECK_PRO)
|
||||
s_lock_epaper_default = !strcmp(wpath, "/lock/placeholder.jpg");
|
||||
s_lock_epaper_default = native;
|
||||
#endif
|
||||
|
||||
s_lock_root = lv_obj_create(lv_layer_top());
|
||||
@@ -43669,10 +43687,16 @@ static void lockscreenShow() {
|
||||
lv_obj_set_size(s_lock_root, sw, sh);
|
||||
lv_obj_set_pos(s_lock_root, 0, 0);
|
||||
#if defined(HAS_TDECK_PRO)
|
||||
lv_obj_set_style_bg_color(s_lock_root,
|
||||
s_lock_epaper_default ? lv_color_white() : lv_color_black(), LV_PART_MAIN);
|
||||
// 1-bit e-paper: the default view is black on white.
|
||||
lv_obj_set_style_bg_color(s_lock_root, native ? lv_color_white() : lv_color_black(), LV_PART_MAIN);
|
||||
#else
|
||||
lv_obj_set_style_bg_color(s_lock_root, lv_color_black(), LV_PART_MAIN);
|
||||
if (native) { // the old wallpaper's dark gradient
|
||||
lv_obj_set_style_bg_color(s_lock_root, lv_color_hex(0x1C232B), LV_PART_MAIN);
|
||||
lv_obj_set_style_bg_grad_color(s_lock_root, lv_color_hex(0x080B0F), LV_PART_MAIN);
|
||||
lv_obj_set_style_bg_grad_dir(s_lock_root, LV_GRAD_DIR_VER, LV_PART_MAIN);
|
||||
} else {
|
||||
lv_obj_set_style_bg_color(s_lock_root, lv_color_black(), LV_PART_MAIN);
|
||||
}
|
||||
#endif
|
||||
lv_obj_set_style_bg_opa(s_lock_root, LV_OPA_COVER, LV_PART_MAIN);
|
||||
lv_obj_clear_flag(s_lock_root, LV_OBJ_FLAG_SCROLLABLE);
|
||||
@@ -43682,7 +43706,7 @@ static void lockscreenShow() {
|
||||
// glow around the lock view.
|
||||
lv_obj_add_flag(s_lock_root, NAV_SKIP_FLAG);
|
||||
|
||||
// Wallpaper, scaled to cover the screen (crop overflow, never letterbox).
|
||||
// A custom wallpaper, scaled to cover the screen (crop overflow, never letterbox).
|
||||
int ww = 0, wh = 0;
|
||||
const uint8_t* wall_data = nullptr;
|
||||
if (s_lock_wall) {
|
||||
@@ -43697,37 +43721,7 @@ static void lockscreenShow() {
|
||||
lvglPsramFree(s_lock_wall);
|
||||
s_lock_wall = nullptr;
|
||||
}
|
||||
if (!strcmp(wpath, "/lock/placeholder.jpg")) {
|
||||
// Default: the pre-dithered RGB565 embed, drawn straight from flash — crisp,
|
||||
// with no JPEG round-trip to re-introduce gradient banding.
|
||||
#if defined(HAS_TDECK_PRO)
|
||||
// The shared default is a 320x240 landscape bitmap. Cover-scaling it onto
|
||||
// this 240x320 portrait panel crops both ends of WADAMESH and magnifies its
|
||||
// padlock. Draw a native monochrome wordmark instead: no crop, no giant icon.
|
||||
lv_obj_t* brand = lv_label_create(s_lock_root);
|
||||
lv_label_set_text(brand, "WADAMESH");
|
||||
lv_obj_set_width(brand, sw - 24);
|
||||
lv_obj_set_style_text_align(brand, LV_TEXT_ALIGN_CENTER, LV_PART_MAIN);
|
||||
lv_obj_set_style_text_font(brand, &lv_font_unscii_16, LV_PART_MAIN);
|
||||
lv_obj_set_style_text_color(brand, lv_color_black(), LV_PART_MAIN);
|
||||
lv_obj_set_style_text_letter_space(brand, 2, LV_PART_MAIN);
|
||||
lv_obj_align(brand, LV_ALIGN_CENTER, 0, 6);
|
||||
#elif defined(TLORA_PAGER)
|
||||
// Native 480x222 crop of the same icon+wordmark, repositioned to the left
|
||||
// (see lockscreen_wallpaper_pager_rgb565.h) -- the shared 320x240 art's
|
||||
// cover-fill on this much wider/shorter panel zoomed it ~1.5x and center-
|
||||
// cropped ~70px off top+bottom, shoving it into the fixed-position text
|
||||
// labels below (reported/photographed). Being screen-native, this needs
|
||||
// no crop math at all: the cover-zoom below naturally computes ~1:1.
|
||||
wall_data = (const uint8_t*)lockscreen_wallpaper_pager_rgb565;
|
||||
ww = LOCKSCREEN_WALLPAPER_PAGER_W;
|
||||
wh = LOCKSCREEN_WALLPAPER_PAGER_H;
|
||||
#else
|
||||
wall_data = (const uint8_t*)lockscreen_wallpaper_rgb565;
|
||||
ww = LOCKSCREEN_WALLPAPER_W;
|
||||
wh = LOCKSCREEN_WALLPAPER_H;
|
||||
#endif
|
||||
} else {
|
||||
if (!native) {
|
||||
s_lock_wall = lockscreenDecodeWallpaper(&ww, &wh); // custom wallpaper (JPEG)
|
||||
wall_data = s_lock_wall;
|
||||
}
|
||||
@@ -43743,10 +43737,7 @@ static void lockscreenShow() {
|
||||
lv_img_set_antialias(img, true);
|
||||
lv_img_set_pivot(img, ww / 2, wh / 2);
|
||||
lv_obj_clear_flag(img, LV_OBJ_FLAG_CLICKABLE);
|
||||
// Background wallpaper: same cover-fill-and-center treatment on every
|
||||
// board, pager included -- only the text labels below get a pager-
|
||||
// specific layout (they're what was actually unreadable/colliding; the
|
||||
// wallpaper crop itself is unchanged from how it's always looked).
|
||||
// Same cover-fill-and-center treatment on every board.
|
||||
uint32_t zx = (uint32_t)sw * 256u / (uint32_t)ww;
|
||||
uint32_t zy = (uint32_t)sh * 256u / (uint32_t)wh;
|
||||
uint32_t zoom = (zx > zy) ? zx : zy; // cover
|
||||
@@ -43754,11 +43745,12 @@ static void lockscreenShow() {
|
||||
lv_img_set_zoom(img, (uint16_t)zoom);
|
||||
lv_obj_align(img, LV_ALIGN_CENTER, 0, 0);
|
||||
}
|
||||
|
||||
#if defined(HAS_TDECK_PRO)
|
||||
// The built-in Pro/Max lock view is black on white for clean 1-bit e-paper.
|
||||
// Custom wallpapers keep the prior white overlay text for contrast.
|
||||
const lv_color_t col = s_lock_epaper_default ? lv_color_black() : lv_color_white();
|
||||
const lv_color_t col = native ? lv_color_black() : lv_color_white();
|
||||
const lv_color_t brand_col = col;
|
||||
const lv_color_t lock_col = col;
|
||||
#elif defined(TLORA_PAGER)
|
||||
// Force a guaranteed-visible white here rather than the shared, user-
|
||||
// customizable touchPrefsGetLockTextColor() -- on this board that pref was
|
||||
@@ -43766,56 +43758,140 @@ static void lockscreenShow() {
|
||||
// background) even at the shared soft-white default (0xE6F2FF), so this
|
||||
// board gets pure white instead of chasing a per-device pref/storage
|
||||
// question for a cosmetic lock screen.
|
||||
const lv_color_t col = lv_color_hex(0xFFFFFFu);
|
||||
const lv_color_t col = lv_color_hex(0xFFFFFFu);
|
||||
const lv_color_t brand_col = lv_color_white();
|
||||
const lv_color_t lock_col = lv_color_hex(0x3D9BFF); // the old wallpaper's padlock blue
|
||||
#else
|
||||
const lv_color_t col = lv_color_hex(touchPrefsGetLockTextColor());
|
||||
const lv_color_t col = lv_color_hex(touchPrefsGetLockTextColor());
|
||||
const lv_color_t brand_col = lv_color_white();
|
||||
const lv_color_t lock_col = lv_color_hex(0x3D9BFF); // the old wallpaper's padlock blue
|
||||
#endif
|
||||
|
||||
// Layout, top down from the status bar: WADAMESH (default view only), the
|
||||
// clock, then a centre row [unread count] padlock [battery] with "Screen
|
||||
// locked" under it, and the unlock hint at the bottom. The short panels (222-
|
||||
// 320 px tall) get a smaller wordmark and padlock and tighter gaps; the centre
|
||||
// row sits at mid-screen unless that would reach the clock.
|
||||
const bool short_panel = sh < 400;
|
||||
const lv_coord_t gap = short_panel ? 4 : 14;
|
||||
const lv_font_t* brand_font = short_panel ? &lv_font_montserrat_16 : &lv_font_montserrat_28;
|
||||
const lv_coord_t lock_w = short_panel ? 40 : 64;
|
||||
const lv_coord_t lock_h = short_panel ? 48 : 78;
|
||||
lv_coord_t y = STATUSBAR_H + gap;
|
||||
|
||||
if (native) {
|
||||
lv_obj_t* brand = lv_label_create(s_lock_root);
|
||||
lv_label_set_text(brand, "WADAMESH");
|
||||
lv_obj_set_style_text_font(brand, brand_font, LV_PART_MAIN);
|
||||
lv_obj_set_style_text_color(brand, brand_col, LV_PART_MAIN);
|
||||
lv_obj_set_style_text_letter_space(brand, short_panel ? 2 : 3, LV_PART_MAIN);
|
||||
lv_obj_align(brand, LV_ALIGN_TOP_MID, 0, y);
|
||||
y += lv_font_get_line_height(brand_font) + gap;
|
||||
}
|
||||
|
||||
s_lock_clock = lv_label_create(s_lock_root);
|
||||
lv_label_set_text(s_lock_clock, "--:--");
|
||||
lv_obj_set_style_text_font(s_lock_clock, &lv_font_montserrat_28, LV_PART_MAIN);
|
||||
lv_obj_set_style_text_color(s_lock_clock, col, LV_PART_MAIN);
|
||||
#if defined(TLORA_PAGER)
|
||||
// Fixed-width box spanning the same 192px the composited icon occupies
|
||||
// (lockscreen_wallpaper_pager_rgb565.h, pasted at x=6 width=192) with
|
||||
// centered text, instead of just left-anchoring the label -- "10:37" and
|
||||
// "8:05" are different pixel widths, so anchoring by the label's own LEFT
|
||||
// edge left the clock's actual visual center drifting with the text
|
||||
// instead of lining up with the icon below it. Centering within a box of
|
||||
// the icon's own width keeps the two centers matched regardless of what
|
||||
// the clock displays.
|
||||
lv_obj_set_width(s_lock_clock, 192);
|
||||
lv_obj_set_style_text_align(s_lock_clock, LV_TEXT_ALIGN_CENTER, LV_PART_MAIN);
|
||||
lv_obj_align(s_lock_clock, LV_ALIGN_TOP_LEFT, 6, 30); // top-left corner, below the 22 px status bar
|
||||
#else
|
||||
lv_obj_align(s_lock_clock, LV_ALIGN_TOP_MID, 0, 30); // below the 22 px status bar
|
||||
#endif
|
||||
// The clock drifts +/-4 px around this for burn-in (lockscreenUpdateClock), so
|
||||
// it sits that much lower to keep clear of the wordmark above.
|
||||
s_lock_clock_y = y + 4;
|
||||
lv_obj_align(s_lock_clock, LV_ALIGN_TOP_MID, 0, s_lock_clock_y);
|
||||
y = s_lock_clock_y + 4 + lv_font_get_line_height(&lv_font_montserrat_28) + (short_panel ? 6 : 18);
|
||||
s_lock_clock_min = -1;
|
||||
s_lock_clock_current = -1;
|
||||
|
||||
// Centre row anchor: the padlock's box (drawn on the default view only; a
|
||||
// custom wallpaper keeps its own picture, and the row keeps its place).
|
||||
lv_obj_t* lock = lv_obj_create(s_lock_root);
|
||||
lv_obj_remove_style_all(lock);
|
||||
lv_obj_set_size(lock, lock_w, lock_h);
|
||||
lv_obj_clear_flag(lock, LV_OBJ_FLAG_CLICKABLE | LV_OBJ_FLAG_SCROLLABLE);
|
||||
const lv_coord_t lock_y = LV_MAX((lv_coord_t)(sh / 2 - lock_h / 2), y);
|
||||
lv_obj_align(lock, LV_ALIGN_TOP_MID, 0, lock_y);
|
||||
if (native) {
|
||||
// Shackle: the top half of a ring, with legs down into the body.
|
||||
const lv_coord_t ring = lock_w * 5 / 8;
|
||||
const lv_coord_t stroke = short_panel ? 4 : 5;
|
||||
const lv_coord_t body_y = lock_h * 7 / 16;
|
||||
lv_obj_t* arc = lv_arc_create(lock);
|
||||
lv_obj_remove_style_all(arc);
|
||||
lv_obj_set_size(arc, ring, ring);
|
||||
lv_obj_align(arc, LV_ALIGN_TOP_MID, 0, 0);
|
||||
lv_arc_set_bg_angles(arc, 180, 360);
|
||||
lv_obj_set_style_arc_width(arc, stroke, LV_PART_MAIN);
|
||||
lv_obj_set_style_arc_color(arc, lock_col, LV_PART_MAIN);
|
||||
lv_obj_set_style_arc_opa(arc, LV_OPA_COVER, LV_PART_MAIN);
|
||||
lv_obj_set_style_arc_opa(arc, LV_OPA_TRANSP, LV_PART_INDICATOR);
|
||||
lv_obj_set_style_bg_opa(arc, LV_OPA_TRANSP, LV_PART_KNOB);
|
||||
lv_obj_clear_flag(arc, LV_OBJ_FLAG_CLICKABLE);
|
||||
for (int side = 0; side < 2; ++side) {
|
||||
lv_obj_t* leg = lv_obj_create(lock);
|
||||
lv_obj_remove_style_all(leg);
|
||||
lv_obj_set_size(leg, stroke, body_y - ring / 2 + 2);
|
||||
lv_obj_set_style_bg_color(leg, lock_col, LV_PART_MAIN);
|
||||
lv_obj_set_style_bg_opa(leg, LV_OPA_COVER, LV_PART_MAIN);
|
||||
lv_obj_set_pos(leg, (lock_w - ring) / 2 + (side ? ring - stroke : 0), ring / 2);
|
||||
}
|
||||
// Body, with a keyhole.
|
||||
lv_obj_t* body = lv_obj_create(lock);
|
||||
lv_obj_remove_style_all(body);
|
||||
lv_obj_set_size(body, lock_w, lock_h - body_y);
|
||||
lv_obj_set_pos(body, 0, body_y);
|
||||
lv_obj_set_style_radius(body, short_panel ? 6 : 10, LV_PART_MAIN);
|
||||
#if defined(HAS_TDECK_PRO)
|
||||
lv_obj_set_style_bg_color(body, lv_color_white(), LV_PART_MAIN);
|
||||
#else
|
||||
lv_obj_set_style_bg_color(body, lv_color_hex(0x141A21), LV_PART_MAIN);
|
||||
#endif
|
||||
lv_obj_set_style_bg_opa(body, LV_OPA_COVER, LV_PART_MAIN);
|
||||
lv_obj_set_style_border_color(body, lock_col, LV_PART_MAIN);
|
||||
lv_obj_set_style_border_width(body, short_panel ? 3 : 4, LV_PART_MAIN);
|
||||
const lv_coord_t hole_d = short_panel ? 7 : 10;
|
||||
lv_obj_t* hole = lv_obj_create(body);
|
||||
lv_obj_remove_style_all(hole);
|
||||
lv_obj_set_size(hole, hole_d, hole_d);
|
||||
lv_obj_set_style_radius(hole, LV_RADIUS_CIRCLE, LV_PART_MAIN);
|
||||
lv_obj_set_style_bg_color(hole, lock_col, LV_PART_MAIN);
|
||||
lv_obj_set_style_bg_opa(hole, LV_OPA_COVER, LV_PART_MAIN);
|
||||
lv_obj_align(hole, LV_ALIGN_CENTER, 0, -hole_d / 2);
|
||||
lv_obj_t* slot = lv_obj_create(body);
|
||||
lv_obj_remove_style_all(slot);
|
||||
lv_obj_set_size(slot, short_panel ? 3 : 4, hole_d + 2);
|
||||
lv_obj_set_style_bg_color(slot, lock_col, LV_PART_MAIN);
|
||||
lv_obj_set_style_bg_opa(slot, LV_OPA_COVER, LV_PART_MAIN);
|
||||
lv_obj_align(slot, LV_ALIGN_CENTER, 0, hole_d / 2 - 1);
|
||||
}
|
||||
|
||||
// The two side readouts each get the whole space between the padlock and their
|
||||
// screen edge, text centred in it: messages on the left, battery on the right.
|
||||
const lv_coord_t side_w = LV_MAX(40, (lv_coord_t)((sw - lock_w) / 2));
|
||||
s_lock_unread = lv_label_create(s_lock_root);
|
||||
lv_obj_set_style_text_font(s_lock_unread, &g_font_16, LV_PART_MAIN);
|
||||
lv_obj_set_style_text_color(s_lock_unread, col, LV_PART_MAIN);
|
||||
#if defined(TLORA_PAGER)
|
||||
// Positioned once the hint label exists below -- see the bottom-right stack
|
||||
// built after `hint` is created.
|
||||
#else
|
||||
lv_obj_align(s_lock_unread, LV_ALIGN_TOP_MID, 0, 68);
|
||||
#endif
|
||||
lv_obj_set_width(s_lock_unread, side_w);
|
||||
lv_obj_set_style_text_align(s_lock_unread, LV_TEXT_ALIGN_CENTER, LV_PART_MAIN);
|
||||
lv_obj_align_to(s_lock_unread, lock, LV_ALIGN_OUT_LEFT_MID, 0, 0);
|
||||
lv_obj_add_flag(s_lock_unread, LV_OBJ_FLAG_HIDDEN);
|
||||
s_lock_unread_n = -1;
|
||||
|
||||
s_lock_batt = lv_label_create(s_lock_root);
|
||||
lv_obj_set_style_text_font(s_lock_batt, &g_font_16, LV_PART_MAIN);
|
||||
lv_obj_set_style_text_color(s_lock_batt, col, LV_PART_MAIN);
|
||||
lv_obj_set_width(s_lock_batt, side_w);
|
||||
lv_obj_set_style_text_align(s_lock_batt, LV_TEXT_ALIGN_CENTER, LV_PART_MAIN);
|
||||
lv_obj_align_to(s_lock_batt, lock, LV_ALIGN_OUT_RIGHT_MID, 0, 0);
|
||||
s_lock_batt_key = -1;
|
||||
|
||||
lockscreenUpdateClock();
|
||||
lockscreenUpdateUnread();
|
||||
lockscreenUpdateBattery();
|
||||
|
||||
lv_obj_t* st = lv_label_create(s_lock_root);
|
||||
lv_label_set_text(st, TR("Screen locked"));
|
||||
lv_obj_set_style_text_font(st, &g_font_16, LV_PART_MAIN);
|
||||
lv_obj_set_style_text_color(st, col, LV_PART_MAIN);
|
||||
#if defined(TLORA_PAGER)
|
||||
s_lock_status = st; // positioned once the hint label exists below -- see the bottom-right stack
|
||||
#else
|
||||
lv_obj_align(st, LV_ALIGN_TOP_MID, 0, 190);
|
||||
#endif
|
||||
lv_obj_align_to(st, lock, LV_ALIGN_OUT_BOTTOM_MID, 0, short_panel ? 6 : 18);
|
||||
|
||||
lv_obj_t* hint = lv_label_create(s_lock_root);
|
||||
useChainedFont(hint);
|
||||
@@ -43835,6 +43911,8 @@ static void lockscreenShow() {
|
||||
lv_label_set_text(hint, TR("double-press d-pad center to unlock"));
|
||||
#elif defined(HAS_WIO_TRACKER_L2)
|
||||
lv_label_set_text(hint, TR("hold the wake button to unlock"));
|
||||
#elif defined(HAS_TDISPLAY_P4)
|
||||
lv_label_set_text(hint, TR("hold the BOOT button to unlock"));
|
||||
#else
|
||||
lv_label_set_text(hint, TR("hold the trackball to unlock"));
|
||||
#endif
|
||||
@@ -43853,26 +43931,13 @@ static void lockscreenShow() {
|
||||
#else
|
||||
lv_obj_set_style_text_opa(hint, LV_OPA_70, LV_PART_MAIN);
|
||||
#endif
|
||||
#if defined(TLORA_PAGER)
|
||||
lv_obj_align(hint, LV_ALIGN_BOTTOM_RIGHT, -6, -8); // bottom-right corner, clear of the icon/clock column above
|
||||
s_lock_hint = hint;
|
||||
// Message count + "Screen locked" stack right-aligned directly above the hint,
|
||||
// each anchored to the one below it (not a fixed y) so the group holds
|
||||
// together and stays right-aligned regardless of label width or whether the
|
||||
// unread badge is visible.
|
||||
lv_obj_align_to(st, hint, LV_ALIGN_OUT_TOP_RIGHT, 0, -4);
|
||||
lv_obj_align_to(s_lock_unread, st, LV_ALIGN_OUT_TOP_RIGHT, 0, -4);
|
||||
#else
|
||||
lv_obj_align(hint, LV_ALIGN_BOTTOM_MID, 0, -8);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void lockscreenHide() {
|
||||
lockscreenUnlockPopupHide();
|
||||
if (s_lock_root) { lv_obj_del(s_lock_root); s_lock_root = nullptr; s_lock_clock = nullptr; s_lock_unread = nullptr;
|
||||
#if defined(TLORA_PAGER)
|
||||
s_lock_status = nullptr; s_lock_hint = nullptr;
|
||||
#endif
|
||||
s_lock_batt = nullptr;
|
||||
}
|
||||
if (s_lock_wall) { lv_img_cache_invalidate_src(&s_lock_wall_dsc); lvglPsramFree(s_lock_wall); s_lock_wall = nullptr; }
|
||||
s_lock_clock_min = -1;
|
||||
@@ -43901,7 +43966,11 @@ static void serviceLockscreen() {
|
||||
if (mm != s_lock_clock_min || (current ? 1 : 0) != s_lock_clock_current)
|
||||
lockscreenUpdateClock();
|
||||
unsigned long now = millis();
|
||||
if (now - s_lock_unread_ms >= 1000) { s_lock_unread_ms = now; lockscreenUpdateUnread(); }
|
||||
if (now - s_lock_unread_ms >= 1000) {
|
||||
s_lock_unread_ms = now;
|
||||
lockscreenUpdateUnread();
|
||||
lockscreenUpdateBattery();
|
||||
}
|
||||
}
|
||||
#endif // CAP_LOCK_SCREEN
|
||||
|
||||
@@ -47331,7 +47400,7 @@ static void powerRebootCb(lv_event_t* e) {
|
||||
// finds the hardware switch — and that is what the T-Display P4 did: no wake
|
||||
// source armed at all, under a toast promising a trackball it does not have
|
||||
// (#310). Boards without the symbol get no Power-off row (see openPowerMenu).
|
||||
#if defined(PIN_USER_BTN) && !defined(HAS_WIO_TRACKER_L2)
|
||||
#if defined(PIN_USER_BTN) && !defined(HAS_WIO_TRACKER_L2) && !defined(HAS_TDISPLAY_P4)
|
||||
static void powerOffCb(lv_event_t* e) {
|
||||
if (lv_event_get_code(e) != LV_EVENT_CLICKED) return;
|
||||
closePowerMenu();
|
||||
@@ -47533,8 +47602,9 @@ static void openPowerMenu() {
|
||||
lv_obj_center(l);
|
||||
return b;
|
||||
};
|
||||
#if !defined(PIN_USER_BTN) || defined(HAS_WIO_TRACKER_L2)
|
||||
#if !defined(PIN_USER_BTN) || defined(HAS_WIO_TRACKER_L2) || defined(HAS_TDISPLAY_P4)
|
||||
// No "Power off" here: nothing on this board can wake it from deep sleep.
|
||||
// (The P4's BOOT button is GPIO35, not one of its LP GPIOs, so it cannot.)
|
||||
// The M9 has a power-cut slider and reset, neither a wakeable GPIO; the L2's
|
||||
// wake button is behind an I2C expander, which cannot wake the ESP32-S3; the
|
||||
// T-Display P4 and Tanmatsu have no user button either. Offering a software
|
||||
@@ -64241,9 +64311,10 @@ void UITask::loop() {
|
||||
s_tb_click_press = tb_pressed && !s_tb_wake_consume;
|
||||
if (s_tb_click_press) { s_tb_last_active_ms = now; noteUserInput(); }
|
||||
}
|
||||
#elif defined(HAS_WIO_TRACKER_L2)
|
||||
#elif defined(HAS_WIO_TRACKER_L2) || defined(HAS_TDISPLAY_P4)
|
||||
// Either physical button wakes/reveals immediately. Continuing to hold for
|
||||
// two seconds toggles the hard lock; releasing early cancels the transition.
|
||||
// The T-Display P4's BOOT button (GPIO35) works the same way.
|
||||
static constexpr uint32_t kL2WakeHoldMs = 2000;
|
||||
static uint32_t s_l2_btn_down_ms = 0;
|
||||
static bool s_l2_press_active = false;
|
||||
@@ -64358,19 +64429,15 @@ void UITask::loop() {
|
||||
// every click. Signed keeps a slightly-ahead stamp negative (= "just had input").
|
||||
if (_screen_timeout_ms > 0 && !_screen_off &&
|
||||
(int32_t)(now - _last_input_ms) >= (int32_t)_screen_timeout_ms) {
|
||||
#if !defined(HAS_TDISPLAY_P4)
|
||||
// The P4 has no unlock path (no button/overlay), so it must NEVER hard-lock, even if an old
|
||||
// pref left the flag set — it always takes the plain screen-off branch below, which wakes on
|
||||
// touch. (Guards the trap; the "Lock when screen off" toggle is also hidden on the P4.)
|
||||
if (s_lock_on_screen_off && !_manual_lock) {
|
||||
// "Lock when screen off": idle dim also hard-locks, so the touchscreen is
|
||||
// inert until a deliberate unlock (trackball hold on the T-Deck, BOOT
|
||||
// press on the V4) — Tim's request to stop pocket-taps while dark. The
|
||||
// !_manual_lock guard stops the Tanmatsu's lit lock screen from re-firing
|
||||
// lockScreen() (and re-lighting) on every idle tick.
|
||||
// press on the V4, holding BOOT on the P4) — Tim's request to stop
|
||||
// pocket-taps while dark. The !_manual_lock guard stops the Tanmatsu's
|
||||
// lit lock screen from re-firing lockScreen() (and re-lighting) on every
|
||||
// idle tick.
|
||||
lockScreen();
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
touchScreenBacklight(false);
|
||||
setCpuForScreen(false); // idle dim (no lock) -> drop to 80 MHz too
|
||||
|
||||
@@ -142,16 +142,12 @@
|
||||
#define CAP_FILESYSTEM 1 // SD_MMC + internal FFat 'storage'
|
||||
#define CAP_GPS 1 // L76K
|
||||
#define CAP_OTA 1 // standalone dual-OTA app
|
||||
// 0, for the same reason as the V4-R8 above: nothing here is wired. There is no
|
||||
// way to REACH the lock (the control-center Lock button is HAS_TDECK_GT911-only,
|
||||
// and the pager/Tanmatsu triggers are their own boards), no unlock gesture (every
|
||||
// unlock path is a trackball / Vol- / d-pad / wake-button branch, and the on-screen
|
||||
// hint falls through to "hold the trackball", which this board does not have), and
|
||||
// the DSEC_LOCK settings body is gated to the T-Deck and M9 -- so declaring the cap
|
||||
// only produced an empty Lock screen settings card (#451). Turning this back on is
|
||||
// a feature: a touch reveal + hold-to-unlock path, a P4 hint string, and the
|
||||
// DSEC_LOCK gates. Until then, do not advertise it.
|
||||
#define CAP_LOCK_SCREEN 0
|
||||
// The BOOT button (GPIO35, PIN_USER_BTN) works like the Wio Tracker L2's wake
|
||||
// button: a press wakes the screen or lights the lock screen, holding it 2 s
|
||||
// locks / unlocks. That is both the way to reach the lock and the deliberate
|
||||
// unlock #451 found missing; the lock hint names the button, and the Lock screen
|
||||
// settings page carries the "Lock when screen off" switch (as on the L2).
|
||||
#define CAP_LOCK_SCREEN 1
|
||||
|
||||
#elif defined(ATTAKY_MESH_SERIES)
|
||||
#define CAP_TOUCH 1
|
||||
|
||||
@@ -97,6 +97,11 @@ set(WADA_DEFS
|
||||
# Detected at runtime; the on-screen keyboard stays while it is away (P4Keyboard.h). ---
|
||||
HAS_TDISPLAY_P4_KEYBOARD=1
|
||||
|
||||
# --- BOOT button (GPIO35, active low) as the wake/lock button, like the Wio Tracker L2's:
|
||||
# a press wakes (or lights the lock screen), a 2 s hold locks / unlocks. GPIO35 is not an
|
||||
# LP GPIO, so it cannot wake deep sleep: UITask keeps the Power-off row off this board. ---
|
||||
PIN_USER_BTN=35
|
||||
|
||||
# --- Board I2C_1 (XL9535 + touch + PCF8563 RTC + BQ27220 gauge) ---
|
||||
PIN_BOARD_SDA=7 PIN_BOARD_SCL=8
|
||||
XL9535_SDA=7 XL9535_SCL=8 XL9535_INT_PIN=5
|
||||
|
||||
Reference in New Issue
Block a user