mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-10-09 03:06:39 +00:00
fix(ui-lvgl): unlock fades away on release, channel names shown as named
- Unlocking fades the lock screen out while the screen underneath drifts into place; the slider unlocks on letting go at the end and springs back when let go earlier - Channel names no longer get a "# " prefix (thread title, channel popup, live share targets) -- "#" marks a hashtag channel; favourite contacts in the live share list are starred instead Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -9,11 +9,14 @@ namespace anim {
|
||||
static const uint32_t POP_MS = 160; // popup / toast in
|
||||
static const uint32_t OUT_MS = 120; // toast out
|
||||
static const uint32_t PAGE_MS = 160; // Home page after a swipe
|
||||
static const uint32_t UNLOCK_MS = 260; // lock screen away
|
||||
static const uint32_t SPRING_MS = 200; // a let-go slider knob back home
|
||||
|
||||
static void setTy(void* o, int32_t v) { lv_obj_set_style_translate_y((lv_obj_t*)o, v, 0); }
|
||||
static void setTx(void* o, int32_t v) { lv_obj_set_style_translate_x((lv_obj_t*)o, v, 0); }
|
||||
static void setOpa(void* o, int32_t v) { lv_obj_set_style_opa((lv_obj_t*)o, (lv_opa_t)v, 0); }
|
||||
static void setBgOpa(void* o, int32_t v) { lv_obj_set_style_bg_opa((lv_obj_t*)o, (lv_opa_t)v, 0); }
|
||||
static void setSlider(void* o, int32_t v) { lv_slider_set_value((lv_obj_t*)o, v, LV_ANIM_OFF); }
|
||||
|
||||
static void run(lv_obj_t* o, lv_anim_exec_xcb_t cb, int32_t from, int32_t to, uint32_t ms,
|
||||
lv_anim_completed_cb_t done = nullptr) {
|
||||
|
||||
@@ -76,7 +76,7 @@ void UITask::channelMenu(int idx) {
|
||||
s_del_armed_ms = 0;
|
||||
s_del_lbl = s_fav_btn = nullptr;
|
||||
char title[40];
|
||||
snprintf(title, sizeof(title), "%s%s", ch.name[0] == '#' ? "" : "# ", ch.name); // "#topic" has its own
|
||||
snprintf(title, sizeof(title), "%s", ch.name); // as named: "#" marks a hashtag channel
|
||||
lv_obj_t* panel = navPopupPanel(title, false);
|
||||
|
||||
// Notifications: three segments in the row (a dropdown's list ran off the
|
||||
|
||||
@@ -237,8 +237,19 @@ void UITask::unlockScreen() {
|
||||
using namespace devview;
|
||||
if (!s_lock) return;
|
||||
lv_indev_wait_release(lv_indev_active()); // the slide isn't also a tap underneath
|
||||
lv_obj_delete_async(s_lock);
|
||||
s_lock = s_lock_clock = s_lock_date = s_lock_unread = s_lock_slider = s_pin_dots = s_pin_msg = nullptr;
|
||||
// The lock's content goes at once and its background fades away as the
|
||||
// screen underneath drifts up into place -- the same cheap cover fade as a
|
||||
// screen change (Anim.h), which deletes the overlay at the end.
|
||||
lv_obj_t* fading = s_lock;
|
||||
for (uint32_t i = 0; i < lv_obj_get_child_count(fading); i++)
|
||||
lv_obj_add_flag(lv_obj_get_child(fading, i), LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_remove_flag(fading, LV_OBJ_FLAG_CLICKABLE);
|
||||
if (_asleep) lv_obj_delete_async(fading);
|
||||
else {
|
||||
anim::run(fading, anim::setBgOpa, LV_OPA_COVER, LV_OPA_TRANSP, anim::UNLOCK_MS, anim::coverDone);
|
||||
if (_body) anim::run(_body, anim::setTy, 12, 0, anim::UNLOCK_MS);
|
||||
}
|
||||
s_lock =s_lock_clock = s_lock_date = s_lock_unread = s_lock_slider = s_pin_dots = s_pin_msg = nullptr;
|
||||
_pin_entry[0] = '\0';
|
||||
if (_screen == SCR_HOME) refreshHome();
|
||||
else if (_screen == SCR_CHATS) buildChats(); // counts moved on while locked
|
||||
@@ -246,9 +257,10 @@ void UITask::unlockScreen() {
|
||||
|
||||
bool UITask::locked() const { return devview::s_lock != nullptr; }
|
||||
|
||||
// From loop() while locked: the knob follows the finger. Tracked from the
|
||||
// touch itself, like the Home page swipe -- LVGL stops feeding a pressed
|
||||
// widget once the finger has moved past its scroll threshold.
|
||||
// From loop() while locked: the knob follows the finger and unlocks when let
|
||||
// go at the end (a knob let go earlier springs back). Tracked from the touch
|
||||
// itself, like the Home page swipe -- LVGL stops feeding a pressed widget
|
||||
// once the finger has moved past its scroll threshold.
|
||||
void UITask::lockPoll() {
|
||||
using namespace devview;
|
||||
static bool s_dragging = false, s_was_down = false;
|
||||
@@ -262,19 +274,22 @@ void UITask::lockPoll() {
|
||||
int32_t knob = lv_area_get_height(&a); // round knob, as tall as the track
|
||||
if (down && !s_was_down) { // a drag starts on the knob only
|
||||
s_dragging = p.y >= a.y1 - 10 && p.y <= a.y2 + 10 && p.x <= a.x1 + knob + 16;
|
||||
if (s_dragging) lv_anim_delete(s_lock_slider, anim::setSlider);
|
||||
}
|
||||
s_was_down = down;
|
||||
if (!down) {
|
||||
if (s_dragging || lv_slider_get_value(s_lock_slider) != 0) lv_slider_set_value(s_lock_slider, 0, LV_ANIM_OFF);
|
||||
if (!s_dragging) return;
|
||||
s_dragging = false;
|
||||
int32_t v = lv_slider_get_value(s_lock_slider);
|
||||
if (v >= 100) unlockScreen();
|
||||
else if (v > 0) anim::run(s_lock_slider, anim::setSlider, v, 0, anim::SPRING_MS);
|
||||
return;
|
||||
}
|
||||
if (!s_dragging) return;
|
||||
int32_t span = lv_area_get_width(&a) - knob;
|
||||
int32_t v = span > 0 ? (p.x - a.x1 - knob / 2) * 100 / span : 0;
|
||||
v = v < 0 ? 0 : v > 100 ? 100 : v;
|
||||
v = v < 0 ? 0 : v >= 92 ? 100 : v; // snaps to the end: let go to unlock
|
||||
lv_slider_set_value(s_lock_slider, v, LV_ANIM_OFF);
|
||||
if (v >= 95) { s_dragging = s_was_down = false; unlockScreen(); }
|
||||
}
|
||||
|
||||
void UITask::refreshLock() {
|
||||
|
||||
@@ -836,8 +836,9 @@ void UITask::navToolsPopup() {
|
||||
_nav_share_lbl = label(list, "", THEME_FONT_SMALL, theme::TEXT);
|
||||
lv_label_set_long_mode(_nav_share_lbl, LV_LABEL_LONG_WRAP);
|
||||
lv_obj_set_width(_nav_share_lbl, LV_PCT(100));
|
||||
// Target: channels, then favourite contacts.
|
||||
char opts[MAX_GROUP_CHANNELS * 24 + 16 * 36];
|
||||
// Target: channels (as named -- "#" marks a hashtag channel), then
|
||||
// favourite contacts (starred, so the two stay apart).
|
||||
char opts[MAX_GROUP_CHANNELS * 24 + 16 * 40];
|
||||
int o = 0, sel = 0;
|
||||
navmap::s_share_n = 0;
|
||||
for (int i = 0; i < MAX_GROUP_CHANNELS && navmap::s_share_n < navmap::SHARE_TARGETS; i++) {
|
||||
@@ -846,7 +847,7 @@ void UITask::navToolsPopup() {
|
||||
if (_prefs->loc_share_target_type == 0 && _prefs->loc_share_channel_idx == i) sel = navmap::s_share_n;
|
||||
navmap::s_share_kind[navmap::s_share_n] = 0;
|
||||
navmap::s_share_ch[navmap::s_share_n++] = (uint8_t)i;
|
||||
o += snprintf(opts + o, sizeof(opts) - o, "%s# %s", o ? "\n" : "", ch.name);
|
||||
o += snprintf(opts + o, sizeof(opts) - o, "%s%s", o ? "\n" : "", ch.name);
|
||||
}
|
||||
int favs = 0;
|
||||
for (int i = 0; i < the_mesh.getNumContacts() && favs < 16 && navmap::s_share_n < navmap::SHARE_TARGETS; i++) {
|
||||
@@ -857,7 +858,7 @@ void UITask::navToolsPopup() {
|
||||
memcmp(_prefs->loc_share_dm_prefix, c.id.pub_key, NodePrefs::FAVOURITE_PREFIX_LEN) == 0) sel = navmap::s_share_n;
|
||||
navmap::s_share_kind[navmap::s_share_n] = 1;
|
||||
memcpy(navmap::s_share_key[navmap::s_share_n++], c.id.pub_key, NodePrefs::FAVOURITE_PREFIX_LEN);
|
||||
o += snprintf(opts + o, sizeof(opts) - o, "%s%s", o ? "\n" : "", c.name);
|
||||
o += snprintf(opts + o, sizeof(opts) - o, "%s" UI_SYMBOL_STAR " %s", o ? "\n" : "", c.name);
|
||||
favs++;
|
||||
}
|
||||
lv_obj_t* tr = lv_obj_create(list);
|
||||
|
||||
@@ -1788,7 +1788,7 @@ void UITask::buildThread() {
|
||||
bool can_send = true;
|
||||
if (_thread_is_channel) {
|
||||
ChannelDetails ch;
|
||||
if (the_mesh.getChannel(_thread_channel, ch)) snprintf(title, sizeof(title), "%s%s", ch.name[0] == '#' ? "" : "# ", ch.name);
|
||||
if (the_mesh.getChannel(_thread_channel, ch)) snprintf(title, sizeof(title), "%s", ch.name); // as named: "#" marks a hashtag channel
|
||||
else snprintf(title, sizeof(title), "Channel %d", _thread_channel);
|
||||
} else {
|
||||
contactName(_thread_key, title, sizeof(title));
|
||||
|
||||
Reference in New Issue
Block a user