Commit Graph

68 Commits

Author SHA1 Message Date
be-nj
8fc7a3887e README: the login is not tied to a particular identity provider
All checks were successful
Build TV app / build (push) Successful in 43s
The server names its issuer and client id; everything after that is OIDC discovery and RFC 8628. Authentik is what this household runs, not a requirement — and the generic M3U source needs no login at all.
2026-08-26 20:16:54 +02:00
be-nj
80b4c0c6cd Show the login link as a QR so nobody races the code
All checks were successful
Build TV app / build (push) Successful in 47s
The identity provider's code lives a minute here, and the screen asked
people to type nine digits into a phone within it. That is the wrong
argument to have: the phone has a camera.

While the login is pending, the QR on the welcome screen points at the
provider's confirmation page with the code already in the URL, instead of at
this TV's own remote. Scanning ends at "confirm"; the digits stay underneath
for whoever prefers them, and the automatic renewal still covers a code that
runs out while somebody walks to the phone.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-26 19:55:58 +02:00
be-nj
06b31f0b9d Record crashes on the device so "two weeks without one" can be checked
All checks were successful
Build TV app / build (push) Successful in 46s
The milestone asks for two weeks in the living room without a crash. Nobody
reads logcat on a TV, and by the time someone says "it was gone yesterday"
the log has rotated — the criterion had no evidence behind it.

CrashLog keeps the last ten crashes in the app's own files: timestamp,
version, and the top of the stack. Nothing is sent anywhere. The settings
show either "Kein Absturz aufgezeichnet" or the newest one, and clicking
the row clears the record — so the two weeks start when you say they do.

Verified by crashing the app on purpose: the entry appears as
"26.08.2026 18:10 · 0.11.5" with the exception below it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-26 19:50:01 +02:00
be-nj
660837c116 Observation sheet for the onboarding test (#21)
All checks were successful
Build TV app / build (push) Successful in 44s
A person who does not know the app sets up the TV while somebody watches and says nothing. The sheet says what to write down, so the result is a list of issues instead of an impression.
2026-08-26 19:36:43 +02:00
be-nj
d269618ebf Work through the 1.0 milestone: focus, backend tests, remote, login code
All checks were successful
Build TV app / build (push) Successful in 53s
#20 Each settings column is a focus group now. The middle column is shorter
than the left, so "down" past its last row used to search wider and land
back in the left column — "Erweitert" was only reachable by going right,
down, left.

#22 The whole backend path had no coverage, which is why an afternoon
against the real instance found three bugs. Parsing moved out of
DispatcharrRepository into DispatcharrJson and is covered by twelve tests
built from the shapes that instance actually returns: pagination, channels
without a uuid or hidden from output, effective vs plain names and logos,
favourites without the key, inactive output profiles, and all three EPG
envelopes the fork has shipped. Android's stub org.json throws in unit
tests, so the real implementation is on the test classpath.
What no test can reach is written down in tests/dispatcharr-checkliste.md.

#24 The remote's channel tab was only ever read in source. Driven through
the DevTools protocol against the real backend it lists 503 channels with
logos and EPG, the search filters, the club chip switches view, and a star
survives the round trip to the backend and back — set and unset. It also
showed the phone still spelling out "BL: Bayer Leverkusen - VfB Stuttgart,
tipico Topspiel der Woche, 16. Spieltag" where the TV shortens to the
fixture; the payload shortens now too.

#23 The TV says "Der alte Code war abgelaufen — neuer Code 566071643"
instead of swapping the digits without a word.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-26 19:33:29 +02:00
be-nj
de6d3a921f What 505 real channels showed that 20 demo ones could not
All checks were successful
Build TV app / build (push) Successful in 42s
The favourite count sat at zero while the backend already had two: the rail
read the favourites off the StateFlow inside the composable instead of
collecting it, so it never recomposed — a regression from making favourites
work for both source types. The list collects again.

Real EPG titles broke the fixture shortener in both directions. "BL: VfB
Stuttgart - Saison 25-26" became a fixture against a season, and
"… FC Bayern München - VfB Stuttgart - 1. Halbzeit" grew a third team; a
season, a matchday, a half or a year is now rejected, and a second dash ends
the away side. The kick-off chip also gave way in the row: the line below
already carries the time, and "Bayer Leverkusen - VfB Stuttgart" needed the
width to fit at all.

Merged provider EPGs list the same programme several times, minutes apart —
the day plan showed The Big Bang Theory three times and two entries marked
as running at once. XmltvParser.collapseDuplicates folds a repeat into the
entry whose slot it falls inside.

The login code expired before anyone could confirm it: Authentik hands out a
minute, and the TV dropped back to step one without a word. It fetches a
fresh code instead, up to eight times.

Tested against the household's own Dispatcharr through api.tv.beckm4nn.net.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-26 16:53:14 +02:00
be-nj
4cb7a6efdb Act on the screen-by-screen review: 17 findings
All checks were successful
Build TV app / build (push) Successful in 43s
Defects. "Kopplung zurücksetzen" now asks first, naming how many phones
would have to scan again — one stray OK used to wipe a working pairing, and
the settings put the focus right on it: entering the screen landed on the
gear, one press down jumped into the right column onto that very action, and
every further press down did nothing. Focus now starts on the first row of
the left column. 1. FC Köln was labelled "EFC". An unreachable source used
to look like an evening without programmes — cached list, empty EPG, club
menus counting down to zero — so both repositories now record when they last
came through, and the top bar says "Server nicht erreichbar · Stand 14:46".
The field labels on "Erweitert" sat on the outline with the border running
through them; they sit above their field now.

Polish. The app opens on the channel list — on the channel last watched,
which survives a restart — instead of the settings gear. Rows without EPG
fill their empty half with the channel's group. The club chip says "ab
15:06" like the row next to it, the club menu carries the club's name
instead of "FCSP", and a fixture title is shortened to the fixture, so
"Pokal: Nordstadt - FC St. P…" became "Nordstadt - FC St. Pauli".
The settings are three columns and no longer scroll (CONTEXT.md's ten-foot
rule).

Features. Favourites work for a plain M3U source too, stored on the device
and mirrored to the phone; they used to exist only with a Dispatcharr login.
The channel keys jump the list by initial letter, left and right jump a
division in the club picker, and right on a channel opens its day plan —
the EPG beyond now/next, which was parsed all along and never shown. When a
club match starts elsewhere the player offers to switch. The remote asked
for a code "unten auf dem TV-Bildschirm" where none was; the welcome screen
shows it now and the wording points at where it is.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-26 15:54:00 +02:00
be-nj
ac90898a46 Smoke test: truncate the demo server log per run
All checks were successful
Build TV app / build (push) Successful in 46s
2026-08-26 14:34:18 +02:00
be-nj
bb6af51788 README: document the test and release scripts
All checks were successful
Build TV app / build (push) Successful in 46s
2026-08-26 14:33:37 +02:00
be-nj
a7d8fcd089 Split the two screens that kept breaking, and let the smoke test reach them
Some checks failed
Build TV app / build (push) Has been cancelled
SettingsScreen and LiveScreen had grown to 760 and 689 lines and were where
most of the last few days' bugs lived. Each is now the screen itself plus
the pieces it composes — club chooser, pickers and rows next to settings,
channel row and cells next to the live list. No behaviour changes: the same
composables, moved, with the visibility widened from private to internal
where a caller now sits in another file.

formatClock existed twice, once per screen, and the move turned that into a
compile error rather than a quiet duplicate. It is one internal function now.

The smoke test seeds the demo playlist into the app's preferences before
launching, so it walks the channel list and the player instead of stopping
at the onboarding screen — the screens this commit moves are now actually
exercised. It also refuses to start when its port is already taken: a
leftover server from an earlier session answered every request with a 404
and the wait loop span forever.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-26 14:33:09 +02:00
be-nj
e35500fa2f CI: cache the JDK, the SDK and Gradle on the runner host
All checks were successful
Build TV app / build (push) Successful in 2m42s
Every push re-installed a JDK, re-downloaded the Android SDK and let Gradle
fetch its distribution and every dependency again — roughly two of the three
minutes a run took, spent on bytes that never change.

The job now mounts a directory from the runner host at /cache and keeps the
JDK, the SDK and GRADLE_USER_HOME there; both setup steps are skipped when
what they install is already present. Tests and the APK build share one
Gradle invocation instead of paying twice for JVM startup and configuration.

Needs the mount whitelisted in the runner's valid_volumes
(/etc/komodo/stacks/gitea/runner-cache/** on diana).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-26 14:15:18 +02:00
be-nj
b52ef79c01 Test the three bugs that reached the living room, and script the release
The rate limit, the version compare and the download check were all wrapped
in Android — a Context, a socket, a file — so none of them had a test, and
all three shipped broken: the remote thrown out after five reconnects
(0.11.1), a truncated APK handed to the installer (0.11.5), and a version
compare that would read 0.11.10 as older than 0.11.9 the moment we get
there.

They are now plain Kotlin in AttemptBudget and UpdateRules, with the clock
injected, and 20 tests covering the failures themselves. AttemptBudget also
prunes expired entries before evicting: dropping only empty queues let the
map grow without bound while every tracked address held one fresh failure.

tests/smoke.sh installs the debug APK on the headless emulator, walks the
first screen with the D-pad and fails on a crash or ANR — the class of bug
unit tests cannot see, and the reason 0.11.0 crashed on startup. Forty
seconds end to end.

tools/release.sh does the bump, tests, signed build, tag, apk branch and
Gitea release in one command. It refuses an unsigned build and never writes
the release notes itself; commit subjects are offered as a draft.

tests/helpers/jdk.sh picks a JDK Gradle can run on: Ubuntu moved
default-java to 25, which fails the build with a bare
"IllegalArgumentException: 25.0.4".

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-26 14:12:51 +02:00
be-nj
f1a6600e42 Emulator helper so tests start in seconds, not minutes
All checks were successful
Build TV app / build (push) Successful in 2m54s
The Google TV emulator was launched by hand with -no-snapshot, which forces
a cold boot every time. tests/helpers/emulator.sh boots from the AVD's
default_boot snapshot (~7s) and refreshes that snapshot on stop, so the next
run stays fast. It also wraps the two things a test run needs afterwards:
installing an APK and pulling a screenshot into tests/runs/.

CONTEXT.md's example dialogue still described Xtream credentials entered
through the Remote, which ADR-0005 and ADR-0007 replaced with device flow and
phone-side onboarding.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-26 13:29:33 +02:00
be-nj
637679fd90 Release 0.11.5
All checks were successful
Build TV app / build (push) Successful in 3m13s
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
v0.11.5
2026-08-26 12:07:24 +02:00
be-nj
cbdac7ddb2 Make the club highlight visible and the updater honest
Three fixes.

The pulse ring never showed. It was drawn on a 30dp canvas inside a box
sized to the 20dp crest, so the parent's constraints shrank the canvas
to 20dp and the crest image covered what was left. The box is now wider
than the crest and the ring has room.

"läuft" was drawn straight onto the row, and a focused row is filled
with the accent colour — red on turquoise. The signal now sits on a
dark chip, which reads on an unfocused row, a selected one and a
focused one alike.

The updater handed the installer whatever had been written so far. It
now checks the response code, downloads to a .part file, compares the
byte count against Content-Length before renaming, and refuses a second
concurrent attempt instead of letting two writers share one file. A
half-written APK leaves the installer spinning with nothing to report,
which is what a hang looks like from the sofa.

Crests are also resampled to 128px with a proper filter when fetched;
Android's 8x downscale from the 330px originals left ragged edges.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-26 12:04:58 +02:00
be-nj
8bf1ed3128 Give Heidenheim its own short label
Two clubs mapped to FCH; Hansa Rostock keeps it, Heidenheim becomes
HDH, which is what its own supporters use anyway.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-26 11:49:37 +02:00
be-nj
3b6a8d7d0a Show crests and league sections when picking a club
All checks were successful
Build TV app / build (push) Successful in 2m53s
The club chooser was a flat list of 56 names in a generic picker
dialog, which is unreadable from a couch. It now has its own dialog
with a crest per row, the short label on the right, and section
headers per division. Enabled clubs in the settings card show their
crest too.

A search field would have been the obvious alternative, but text
entry on a remote is exactly what the Ten-Foot rule rules out, so
grouping plus crests carries the recognition instead.

Also adds tests/demo, a generator for neutral playlist and EPG data
so screenshots never carry real channel names.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
v0.11.4
2026-08-26 11:42:18 +02:00
be-nj
e491f8e50f Highlight a club menu while its match is on or about to start
All checks were successful
Build TV app / build (push) Successful in 3m6s
The rail entry showed a plain hit count, which says nothing about whether
that hit is happening now or six hours from now. It now turns into a red
dot with "läuft" while a match is running, and an accent dot with "gleich"
within half an hour of kick-off — the only two moments where the menu is
worth interrupting for. A one-minute ticker re-evaluates it so the state
appears on its own.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
v0.11.3
2026-08-26 10:45:15 +02:00
be-nj
56b5d3f0b0 Stop the socket timeout from killing the remote mid-session
All checks were successful
Build TV app / build (push) Successful in 2m55s
Issue #1's fix gave accepted sockets a read deadline so idle connections
could no longer pin threads — but NanoHTTPD's 5 s default also applies to
the long-lived WebSocket, and pings only ran every 8 s. The remote was
therefore dropped roughly five seconds into every session, right after a
command or two, with no close frame.

The deadline stays (that was the point) but is now 40 s, comfortably above
the ping interval, so pongs keep an active session alive while a truly idle
socket still gets reaped.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
v0.11.2
2026-08-26 10:33:39 +02:00
be-nj
b0b8f8801d Stop throwing out honest remotes, and mirror club menus to the phone
All checks were successful
Build TV app / build (push) Successful in 4m39s
The rate limit charged every hello, not just failed ones. The phone remote
reconnects on any network hiccup, so five reconnects in a minute — entirely
normal — got it kicked with "zu viele Versuche". Only failed authentication
costs budget now, and a success clears the address.

The club menus existed only on the TV. The phone now receives them and
shows a chip per club next to Alle/Favoriten, listing the matching channels
with kick-off time instead of the usual now/next.

Settings: the club row showed an "An" pill although it can only ever
remove, which read like a toggle. It is a remove icon now.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
v0.11.1
2026-08-26 10:25:22 +02:00
be-nj
9a0fa37e55 Club menus look ahead to midnight and count repeat broadcasts
All checks were successful
Build TV app / build (push) Successful in 3m9s
A three-hour window was empty most of the day, which is exactly when
someone wants to know whether their club plays tonight. The scan now runs
until midnight, never less than three hours, so a late-evening question
still covers the rest of the night.

A channel can carry several of the club's broadcasts in one evening — a
preview at 18:20 and the match at 21:45 on the same station. The row names
the next one and appends "+n weitere" instead of silently hiding the rest,
so the list stays a channel list where one click means one station.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
v0.11.0
2026-08-26 10:01:14 +02:00
be-nj
73f6dbba75 Surface failed refreshes instead of swallowing them
All checks were successful
Build TV app / build (push) Successful in 2m54s
Favourites and stream profiles were refreshed inside a bare runCatching,
so when they failed nothing was logged and the app just showed a stale
cached list. An expired login now always raises the re-login screen, even
when cached channels could still be displayed, and the settings gained a
"Senderliste neu laden" row for a manual retry.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
v0.10.6
2026-08-26 03:59:25 +02:00
be-nj
f6f6a2499f Stop the CI from re-fetching crests, cache their URLs instead
All checks were successful
Build TV app / build (push) Successful in 2m49s
Fetching 56 images on every run earned nothing but rate limits, and the
CI artefact is a test build that does not need the badges — the shield
fallback covers it. The resolved image URLs are cached in
tools/crest-sources.json, which is plain text and safe to commit, so a
local run needs one request per club instead of two and can resume after
a rate limit. The artwork itself stays out of the repository.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-26 03:42:49 +02:00
be-nj
8aa3a4da02 Ship the real club crests in the APK, and fix the CI licence step
All checks were successful
Build TV app / build (push) Successful in 4m15s
Resolving crests from Wikipedia at runtime never produced a visible badge
on the TV and left nothing in the log to debug, so the shield fallback was
all anyone ever saw. They are now downloaded once at build time by
tools/fetch-crests.py into assets/crests (git-ignored, so no trademarked
artwork is committed) and loaded from there — instant, and independent of
the network.

CI: accepting SDK licences by piping "yes" into sdkmanager died of SIGPIPE
(exit 141) under pipefail; the licence hashes are written directly now.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
v0.10.5
2026-08-26 03:31:06 +02:00
be-nj
b7ee0523d1 CI: build without marketplace actions
Some checks failed
Build TV app / build (push) Failing after 21s
The runner resolves bare action names against this Gitea, and even with
full GitHub URLs it fails on annotated tags (unsupported object type).
The image also ships neither a JDK nor an Android SDK, so the job never
had a chance. Everything is plain shell now: shallow checkout, JDK 17,
command-line SDK tools, tests, debug APK.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-26 03:10:43 +02:00
be-nj
a3105925bb Make a waiting update visible instead of hiding it in the settings
Some checks failed
Build TV app / build (push) Failing after 5s
The start-up check already ran, but its result only showed as a badge for
whoever happened to open the settings. A chip in the top bar now says
"Update <version>" and leads straight there, and the check repeats every
six hours because a TV keeps the same process alive for days.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
v0.10.3
2026-08-26 03:07:12 +02:00
be-nj
7f1dff5661 Real club crests, and no more crash on "Verein hinzufügen"
Some checks failed
Build TV app / build (push) Failing after 5s
Crests are resolved from the German Wikipedia page summary at runtime and
cached per device, so nothing copyrighted is stored in the repository. The
coloured shield remains as the fallback while the badge loads or when a
club has none.

The add dialog crashed for the same reason the rail did: it focused a row
that only exists when something is preselected, and adding a club has no
preselection. It now also scrolls, which 56 clubs rather need.

CI: this Gitea resolves bare action names against itself, so the workflow
now uses full GitHub URLs, and it runs the unit tests too.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
v0.10.2
2026-08-26 02:59:23 +02:00
be-nj
869060c56f Pick clubs from the top three divisions, and stop the rail from crashing
Some checks failed
Build TV app / build (push) Failing after 2s
The club shortcut now offers every club of the first three German
divisions instead of two hard-coded ones. Up to three can be active at
once; benjamin and tobiasb still start with Hansa and the VfB switched on.

Also fixes a crash on the left jump out of the channel list: the jump
targeted a FocusRequester bound to the selected rail row, and a row that
is scrolled out of a LazyColumn is not composed, so requesting focus on it
threw. Jumps are now attempted and fall back to normal focus movement.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
v0.10.1
2026-08-26 02:54:04 +02:00
be-nj
7ad7f5172e Club shortcut: a rail group for "where is my club on tonight"
Some checks failed
Build TV app / build (push) Failing after 2s
Adds an optional rail entry per club that lists every channel whose EPG
mentions the club within the next three hours, with the matching kick-off
instead of the usual Now/Next. Only sport and free-to-air groups are
scanned (NFL excluded), so the scan stays cheap and quiet.

Which clubs appear is a per-TV setting: the signed-in viewer's own club is
on by default, and every club can be switched on or off under Einstellungen
-> Vereinsmenüs, so a household can follow more than one.

Crests are trademarks, so the icon is a plain shield in the club colours.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
v0.10.0
2026-08-26 02:47:06 +02:00
be-nj
753ab3a3ab Follow the repo move to the be-nj organisation
Some checks failed
Build TV app / build (push) Failing after 2s
Updater and README point at the new path. The old one redirects, but the
updater should not depend on that. Also drops a stale GitHub-specific
Accept header.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
v0.9.2
2026-08-26 02:33:47 +02:00
be-nj
f157323626 fix(live): returning from playback keeps the group you were in
Some checks failed
Build TV app / build (push) Failing after 2s
The rail opens whatever gets focused, so when the player closed and focus
landed on "Alle Sender", the view silently switched away from the group
the viewer had been browsing. A restore flag now suppresses that
auto-select until focus has been placed on the channel that was watched.

Completes #13.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
v0.9.1
2026-08-26 02:20:17 +02:00
be-nj
c0adce2b09 Resolve the full review backlog (issues #1-#13)
Some checks failed
Build TV app / build (push) Failing after 2s
Control server security and robustness:
- Socket read timeout, handshake deadline and a client cap so an idle or
  hostile connection can no longer pin threads forever (#1)
- Per-address rate limiting that counts every failed hello, Origin
  checking on the upgrade, and a separate revocable session token for
  code-authenticated clients so the guessable path no longer yields the
  QR credential (#2)
- Credentials excluded from cloud backup and device transfer, constant
  time comparisons, and a pairing reset in the settings (#3)
- Playlist fetches restricted to http(s), capped at 24 MB and bounded by
  an overall transfer deadline (#4)
- Port conflicts and MediaSession id collisions no longer crash the app;
  the remote degrades to unavailable with a plain-language note (#11)

Player:
- Seeking no longer collapses to position 0 when the duration is unknown
  (#5)
- Pause acts on playWhenReady, so pausing during a stall works and
  playback cannot resume in the background after leaving the app (#6)
- Playback failures stay on screen with a retry action instead of
  silently dropping back to the list (#7)
- Reconnects are spaced 1s/3s/8s and re-entering the channel just closed
  waits out a short grace period, which is what the provider needs to
  release the previous session (#12)

Channel list and remote:
- Leaving playback returns to the channel the viewer came from (#13)
- The remote only rebuilds its list when the data changed, never
  overwrites a focused input and carries indices instead of scanning (#8)
- Pairing retry reconnects properly, resets its backoff and validates the
  code before spending an attempt (#9)
- M3U parsing keeps commas in names, strips a BOM and rejects payloads
  that are not playlists, covered by unit tests under tests/ (#10)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
v0.9.0
2026-08-26 02:14:48 +02:00
be-nj
7abd4b2a48 README: generic group names in screenshots, consistent captions
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-26 01:55:15 +02:00
be-nj
f69ae2f437 README: screenshots as 2x2 grid
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-26 01:43:14 +02:00
be-nj
01a76bffcd README: welcome screen screenshot (QR and LAN address pixelated)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-26 01:42:49 +02:00
be-nj
13352994e4 README: all screenshots full width
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-26 01:42:05 +02:00
be-nj
6acbe77200 README: overlay screenshot (scene pick)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-26 01:41:16 +02:00
be-nj
7da6f5c69f README: brighter player screenshot
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-26 01:36:11 +02:00
be-nj
e66c8a863b Overlay readability on bright video: brighter times, translucent progress track
Some checks failed
Build TV app / build (push) Failing after 2s
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
v0.8.6
2026-08-26 01:32:34 +02:00
be-nj
ca401e8ca3 README for humans: German, screenshots, install guide
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-26 01:30:29 +02:00
be-nj
844ea928ef Channel number in the player overlay (inline before the name)
Some checks failed
Build TV app / build (push) Failing after 3s
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
v0.8.5
2026-08-26 01:27:50 +02:00
be-nj
95f8793938 Bare, larger channel logos (no tile box)
Some checks failed
Build TV app / build (push) Failing after 2s
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
v0.8.4
2026-08-26 01:20:22 +02:00
be-nj
1757d8015d Move update source to Gitea (git.beckm4nn.net)
Some checks failed
Build TV app / build (push) Failing after 3s
Releases API for the version check; the APK itself is served from the
orphan 'apk' branch of the public repo (asset uploads need a token,
raw files do not). Transitional GitHub release carries this change so
existing installs hop over.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
v0.8.3
2026-08-26 01:16:38 +02:00
be-nj
7c1f8d2c8b Channel rows with real logos (Entwurf A), no focus scale clipping
- Rows carry the Dispatcharr channel logo in a small tile (initials as
  fallback), sit on a surface instead of transparent black, and get the
  accent focus border; the group subline is gone — the logo carries
  channel identity.
- Focus scale disabled on settings rows, picker options, rail items and
  channel rows: the grown surface got clipped by its parent.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-26 01:12:07 +02:00
be-nj
3068eaea19 Picker with fullscreen scrim, framed QR tile
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-26 01:07:11 +02:00
be-nj
5b6cebd041 Settings: Wiedergabe card + picker dialogs instead of chip walls
- Quelle and Stream-Qualität move out of Konto into their own
  Wiedergabe card; Konto is account + Abmelden only.
- Choices open a TV-style picker dialog (focus starts on the current
  value, Back closes) with the current value + drawn caret shown at
  the row's trailing edge.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-26 01:01:38 +02:00
be-nj
5de71193ad fix: settings option chips (blob layout), real gear icon, overlay EPG filter, installer on main thread
- SegmentedRow lays label above wrapping option chips instead of
  squeezing them into the trailing slot (long profile names collapsed
  the label and blew the pill up into a blob).
- Gear icon: thick ring + stubby teeth instead of sun rays.
- Player overlay filters EPG placeholders and next==now duplicates
  like the channel list.
- Updater: startActivity from Dispatchers.Main — firing it from the IO
  dispatcher stalled the first install attempt.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-26 00:55:47 +02:00
be-nj
deca5bd0cb fix(live): left lands on the selected group, right enters a fresh group at the top
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-26 00:50:36 +02:00
be-nj
a4391740ec Settings redesign: cards with focusable rows, segmented controls, gear button
- Settings page follows the Google TV pattern: Konto / App / Handy-
  Fernbedienung cards, each row a full-width focus target with label,
  subtitle and trailing value.
- Quelle and Stream-Qualität are segmented controls switched with
  left/right inside the focused row (click cycles).
- Account row with initial avatar, Abmelden as red row, update row
  with version badge; Update installieren only when one is available.
- Top bar: drawn gear icon button replaces the text pill.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-26 00:48:14 +02:00
be-nj
11a8056ce2 fix(player): opening key-up no longer clicks the freshly focused pause button
The key-down that opens the overlay is consumed by the activity, but its
key-up arrived after the play button grabbed focus and clicked it —
instant pause right after the overlay appeared. The overlay now swallows
select-releases whose press it never saw.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-26 00:32:22 +02:00