Commit graph

6 commits

Author SHA1 Message Date
ScreenTinker c94757fc97 fix(android): per-zone rotation + stop fullscreen controller in multi-zone
From Chris's live debug logs on the L-Bar layout:
- ZoneManager only rendered the FIRST assignment per zone -> the Main zone (3
  images) never rotated ('says it's switching but it's not'). Now each zone
  cycles its own assignments: images/widgets on a duration timer, videos on
  end (single-item zones still loop).
- The fullscreen PlaylistController kept running BEHIND the zones (playItem every
  10s, would leak audio for a zone video) because startIfNeeded() ran after every
  playlist update. Now only start it when not in multi-zone (zoneManager.hasZones).
- renderAssignments still called container.removeAllViews() (the same static-view
  nuke the cleanup() fix addressed) -> now removes only its own zone views.
2026-06-08 22:19:25 -05:00
ScreenTinker 73912d5f58 feat(debug): live per-device debug logging toggle on the device screen
Checkbox on the device-detail page streams the Android player's player/zone logs
live (no adb). Transient (off on reconnect), not persisted.

- Android: DebugLog util (logcat + optional socket emit); 'set_debug' command wires
  the sink + flag; key player/zone decisions (layout mode, playItem, per-zone
  render) emit through it.
- Server: relay device:log -> dashboard workspace room as dashboard:device-log.
- Dashboard: 'Debug logging' checkbox sends set_debug; live log panel streams lines
  (rendered via textContent; capped at 500).
2026-06-08 21:49:03 -05:00
ScreenTinker 911cd07951 fix(android): render widgets in fullscreen / single-zone layouts
Widgets worked in multi-zone layouts (ZoneManager renders them in a WebView) but
were broken in "default fullscreen" (no layout) and the fullscreen template (a
single-zone layout) - both take the single-zone PlaylistController path, which:
  1) called getString("content_id"), throwing on a widget assignment (no
     content_id) - in both the playlist builder AND the pre-download loop, which
     could break the whole fullscreen playlist; and
  2) had no widget render case in playItem (so a widget never displayed).

Fix:
- PlaylistItem gains widgetId/widgetType + isWidget; the builder reads them and
  tolerates a missing content_id.
- playItem renders a widget fullscreen via MediaPlayerManager.showWidget() (loads
  /api/widgets/:id/render in the full-screen WebView, mirroring ZoneManager).
- Widgets auto-advance on their duration like images.
- Pre-download loop skips widget assignments (no file to fetch).

Compile-checked; signed APK builds. Needs on-device check: a widget plays in
default-fullscreen and the fullscreen template, and mixed widget+media playlists
advance correctly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 20:07:23 -05:00
ScreenTinker cd6e39a4a7 Fix Android app OOM crash on 4K images and crash loop recovery
A 4K image assigned to a 1080p display decoded as a ~33 MB ARGB_8888
bitmap and OOM'd. Worse, the cached playlist on disk meant relaunch
hit the same image and crashed again — only a reinstall recovered.

New ImageLoader utility reads bounds via inJustDecodeBounds, computes
inSampleSize against the device screen (or zone size for multi-zone
layouts), and returns null on OOM/Throwable so callers skip the item
instead of crashing. MediaPlayerManager exposes an onImageError
callback wired to playlistController.next() so a bad item advances
the playlist. The cached-playlist restore in onCreate now catches
Throwable (was Exception) and clears the cache on any failure,
breaking the crash loop. android:largeHeap="true" added as belt and
braces.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 10:13:10 -05:00
ScreenTinker dc7450b6a7 Offline resilience: persist playlist cache for cold-start recovery
Web player:
- Cache playlist JSON to localStorage on every update
- Restore and start playing immediately on boot before connecting
- Clear cache on unpair/reset

Android app:
- Cache playlist JSON to EncryptedSharedPreferences on every update
- Restore cached playlist on cold-start, play from disk-cached content
- Update cache on content deletion, clear on unpair

Server (device socket):
- Fingerprint reconnect: issue fresh token instead of rejecting
- Send device:paired on fingerprint recovery for claimed devices
- Add status logging and dashboard notification on fingerprint reconnect

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 21:49:45 -05:00
ScreenTinker 1594a9d4a4 Initial open source release
ScreenTinker - open source digital signage management software.
MIT License, all features included, no license gates.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-08 12:14:53 -05:00