ML-167: presto performance improvements

This commit is contained in:
Claudio Ortolina
2026-05-06 07:24:27 +01:00
parent 154c3d9078
commit c550cb8c35
2 changed files with 151 additions and 30 deletions
+88 -30
View File
@@ -127,6 +127,8 @@ MONTH_NAMES = [
# Touch debounce (milliseconds)
DEBOUNCE_MS = 300
DRAG_REDRAW_MS = 40
DRAG_REDRAW_PX = 8
# WiFi connection timeout (seconds)
WIFI_TIMEOUT = 30
@@ -164,9 +166,11 @@ records_error = False # True if API call failed
scroll_offset = 0 # Pixel scroll position for day view
_visible_count = 1 # How many records fit on screen (set during draw)
_dragging = False # True while fast scroll redraws are active
_content_height = 0 # Cached total record list height
# Touch debounce
_last_touch = 0
_last_drag_redraw = 0
# Display sleep state
_last_activity = 0
@@ -539,6 +543,21 @@ def fetch_records(year, month, day):
return [], True
def set_day_records(recs, had_error):
"""Set day-view records and prepare display caches."""
global records, records_error, scroll_offset, _content_height
records = recs
records_error = had_error
scroll_offset = 0
if had_error:
_content_height = 0
return
prepare_records_for_display()
def fetch_thumbnail(url):
"""Fetch a JPEG thumbnail from the given URL.
@@ -933,7 +952,7 @@ def _draw_record_list():
visible_count = 0
for rec in records:
row_h = _record_row_height(rec)
row_h = rec.get("_row_height", THUMB_SIZE + 8)
row_bottom = cy + row_h
if row_bottom <= RECORD_START_Y:
@@ -960,28 +979,56 @@ def _draw_record_list():
def _max_scroll_offset():
"""Return the maximum pixel scroll offset for the current records."""
viewport_h = HEIGHT - RECORD_START_Y - 28
content_h = 0
return max(0, _content_height - viewport_h)
def prepare_records_for_display():
"""Cache display fields, row heights, and thumbnails for current records."""
global _content_height
display.set_font("bitmap8")
for rec in records:
content_h += _record_row_height(rec)
_content_height = 0
return max(0, content_h - viewport_h)
for rec in records:
_prepare_record_for_display(rec)
_content_height += rec.get("_row_height", THUMB_SIZE + 8)
preload_record_thumbnails()
gc.collect()
def _prepare_record_for_display(rec):
"""Prepare one record's display text and row height."""
title = display_text(rec.get("title", "Unknown Title"))
artists = rec.get("artists", [])
artist_str = display_text(", ".join(artists)) if artists else ""
meta_text = _record_meta_text(rec)
rec["_display_title"] = title
rec["_display_artists"] = artist_str
rec["_display_meta"] = meta_text
rec["_thumb_url"] = _record_thumbnail_url(rec)
rec["_row_height"] = _record_row_height(rec)
def preload_record_thumbnails():
"""Fetch thumbnail bytes before the first day-view draw."""
for rec in records:
if rec.get("micro_cover_url", ""):
_record_thumbnail_data(rec)
def _record_row_height(rec):
"""Calculate a record row height without drawing it."""
display.set_font("bitmap8")
min_h = THUMB_SIZE + 8
title = display_text(rec.get("title", "Unknown Title"))
title = rec.get("_display_title", display_text(rec.get("title", "Unknown Title")))
ty = _wrapped_line_count(title, TEXT_W, scale=1) * 12
artists = rec.get("artists", [])
if artists:
artist_str = display_text(", ".join(artists))
artist_str = rec.get("_display_artists", "")
if artist_str:
ty += 2 + _wrapped_line_count(artist_str, TEXT_W, scale=1) * 12
if _record_meta_text(rec):
if rec.get("_display_meta", _record_meta_text(rec)):
ty += 2 + 12
content_h = max(THUMB_SIZE, ty) + 10
@@ -1016,11 +1063,7 @@ def _record_thumbnail_data(rec):
if cached is not None:
return cached
thumb_url = (
rec.get("micro_cover_url", "")
or rec.get("mini_cover_url", "")
or rec.get("thumb_url", "")
)
thumb_url = rec.get("_thumb_url", "") or _record_thumbnail_url(rec)
if not thumb_url:
return None
@@ -1033,6 +1076,15 @@ def _record_thumbnail_data(rec):
return data
def _record_thumbnail_url(rec):
"""Return the preferred cover URL for a record row."""
return (
rec.get("micro_cover_url", "")
or rec.get("mini_cover_url", "")
or rec.get("thumb_url", "")
)
def _draw_record_row(rec, y):
"""Draw a single record row. Returns the Y position after the row
(including separator), so the next row can be positioned correctly
@@ -1047,24 +1099,22 @@ def _draw_record_row(rec, y):
jpeg_data = _record_thumbnail_data(rec)
if jpeg_data is not None:
draw_jpeg(jpeg_data, THUMB_MARGIN, thumb_y, THUMB_SIZE, THUMB_SIZE)
gc.collect()
else:
_draw_placeholder(THUMB_MARGIN, thumb_y, THUMB_SIZE, THUMB_SIZE)
# Title (starts at same height as thumbnail)
title = display_text(rec.get("title", "Unknown Title"))
title = rec.get("_display_title", display_text(rec.get("title", "Unknown Title")))
display.set_font("bitmap8")
ty = y + 4
ty = draw_wrapped(title, TEXT_X, ty, TEXT_W, _pen_title, scale=1)
# Artists
artists = rec.get("artists", [])
if artists:
artist_str = display_text(", ".join(artists))
artist_str = rec.get("_display_artists", "")
if artist_str:
ty += 2
ty = draw_wrapped(artist_str, TEXT_X, ty, TEXT_W, _pen_artist, scale=1)
meta_text = _record_meta_text(rec)
meta_text = rec.get("_display_meta", _record_meta_text(rec))
if meta_text:
ty += 2
ty = draw_wrapped(meta_text, TEXT_X, ty, TEXT_W, _pen_dim_text, scale=1)
@@ -1211,8 +1261,7 @@ def handle_month_touch(x, y):
# Fetch from API
recs, had_error = fetch_records(view_year, view_month, day_num)
records = recs
records_error = had_error
set_day_records(recs, had_error)
# Render day view
draw_day_view()
@@ -1227,8 +1276,7 @@ def handle_day_touch(x, y):
if records_error:
draw_status("Retrying...")
recs, had_error = fetch_records(view_year, view_month, selected_day)
records = recs
records_error = had_error
set_day_records(recs, had_error)
draw_day_view()
@@ -1251,7 +1299,7 @@ def main():
global state, view_year, view_month, _last_touch
global selected_day, records, records_error, scroll_offset
global _dragging
global _last_activity
global _last_activity, _last_drag_redraw
# -- Init display --
init_display()
@@ -1285,8 +1333,7 @@ def main():
MONTH_NAMES[view_month - 1], today_day, view_year
))
recs, had_error = fetch_records(view_year, view_month, today_day)
records = recs
records_error = had_error
set_day_records(recs, had_error)
draw_day_view()
_last_activity = time.ticks_ms()
@@ -1334,6 +1381,7 @@ def main():
pending_delta = 0
dragged = False
_dragging = False
_last_drag_redraw = time.ticks_ms()
while True:
touch_point = read_touch()
if touch_point is None:
@@ -1344,18 +1392,28 @@ def main():
dragged = True
pending_delta += last_drag_y - current_y
if abs(pending_delta) >= 3:
now = time.ticks_ms()
redraw_due = time.ticks_diff(now, _last_drag_redraw) >= DRAG_REDRAW_MS
if abs(pending_delta) >= DRAG_REDRAW_PX and redraw_due:
max_offset = _max_scroll_offset()
new_offset = min(max(0, scroll_offset + pending_delta), max_offset)
if new_offset != scroll_offset:
scroll_offset = new_offset
_dragging = True
draw_day_view()
_last_drag_redraw = now
pending_delta = 0
last_drag_y = current_y
time.sleep(0.01)
if pending_delta:
max_offset = _max_scroll_offset()
new_offset = min(max(0, scroll_offset + pending_delta), max_offset)
if new_offset != scroll_offset:
scroll_offset = new_offset
_dragging = True
if _dragging:
_dragging = False
draw_day_view()