Focused-card rows now animate the newly focused card to the left edge
(animateScrollToItem) instead of the abrupt bring-into-view jump -
SmartTube-style easing. Text inside a focused (white) card flips to a
dark gray-on-white palette instead of staying light gray. LEFT on the
first card of a row/chain opens the menu drawer.
Drop the always-visible sidebar: content is now full width so ~4.5
compact cards fit per row (width derived from the screen). A slide-in
menu drawer opens via the avatar (BACK/LEFT close it) and carries the
destinations + sign out with legible labels (#B0B0B0) replacing the
illegible dark-grey rail. Cards no longer scale on focus: they flip
to a white background with dark text and a white frame like
SmartTube. Grids move to 3 columns with the freed width.
Signing out and logging in as another account kept showing the
previous account's videos: the list ViewModels live in the activity
store and are keyed by destination only. A session epoch now
increments on logout and on each successful login; every ViewModel
key, grid scroll state and per-item focus map is keyed by it, so an
account switch starts from genuinely fresh data.
Claude Code drove the emulator through the TESTS.md checklist
(reports/ux-2026-10-10.md) and found the release blockers. Fixes:
player ignores the D-pad after controller auto-hide (BUG-2, focus +
key forwarding: CENTER play/pause, LEFT/RIGHT seek, others show
controls), Channels 404 for email logins (BUG-1, authenticate the
users/me call at login), focus + history lost after BACK (BUG-3/7,
restore token re-focuses the opened card and History/Continue
watching refresh), Home rows clipped below 1080px (BUG-4, scrollable
LazyColumn), text-field D-pad focus traps (BUG-5, IME actions + key
escapes), Continue watching started at 0:00 and overwrote server
position (BUG-6, resume from userHistory + persist on exit), leaked
report timer (BUG-8), token sent to third-party media hosts (BUG-9,
ResolvingDataSource appends videoFileToken per request, Bearer only
for instance host), player error Retry (BUG-10), raw error strings
(BUG-13), y-ago format bug (BUG-14), sign-out double press (BUG-15),
T18 expectation corrected (server omits private videos from history).
Verified on emuluator: CENTER pauses + shows controller; BACK returns
to refreshed Continue watching with progress bars.
The home screen is now stacked horizontal rows ('Continue watching'
with red progress bars from server-reported positions, 'New videos'
paged) instead of one tall list - matching the SmartTube look the app
is modeled on. The player renders as an overlay so the list beneath
keeps its scroll and focus across BACK (was resetting to the top),
grid scroll state is saved per destination, cards render focus
scale/border via tv-material, thumbnails carry relative dates and
privacy badges only where meaningful, overscan margins guard the 1080p
safe area, and the setup screen got a password reveal, clipboard paste
helpers and an always-focusable validating Sign in.
UX review by Claude Opus 5.5 (claude CLI) on emulator screenshots;
remaining suggestions are triaged in BACKLOG.md.
Releases need more than eyeballs: scripts/e2e-api-check.sh now runs
18 assertions over the live instance (login/refresh, listings, private
rows, subscriptions incl. remote channels, watching + stored position,
file token, playlist reachability) and TESTS.md defines the manual
D-pad checkout that a script cannot do.
Also switch the channels screen to the user's own channels (the
search-based local listing rejects empty queries) and resolve the real
account name at login since logins accept email addresses.
Composable API mismatches with tv-material 1.0.1: NavigationDrawerItem
takes leadingContent/content (not icon/label), Card needs no shape.
Move VideoListItem to top level so its supertype reference resolves.
Pass onOpenVideo by name because the trailing lambda slot on
VideoListScreen goes to the non-functional viewModel parameter.
Nullable search param on local channel listings; make StateFlow
collection use collectAsState directly to avoid a JVM signature clash.
Verified by building app-debug.apk inside the container (JDK 21
installed there for this purpose).
Start the SmartTube-inspired PeerTube TV client as a Kotlin + Compose
for TV app. It targets any PeerTube instance (v1 API), with JTube as
the default, and covers login 0, local/own video listings 1-2, search
3, subscriptions 4, server-backed history 5 and HLS/progressive
playback with watching reports 6.
Password is only used for the OAuth password grant and never stored;
tokens are kept in EncryptedSharedPreferences. Building needs JDK 17+
(see README); the Gradle wrapper is checked in so no local Gradle is
required.