You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
TV browse parity: files, search, history, trash, settings vs the 34-capture oracle #33
The browse surface reaches Android-native parity with the product contract and the 34-capture behavior oracle: files, search, history, trash, and account/settings all preserve raw file data and Compose for TV interaction.
Scope
Files (04–06b): root/nested browsing, LazyColumn with stable keys, cursor paging, sort + refresh, watched/progress indicators, folder/video branching, unsupported-type state, long-press action menu (VLC handoff with original stream URL, watched toggle gated on use_start_from, trash/delete)
Search (07–07c): system IME only, no app-drawn key grid and no mic affordance; debounced/paged results in standard file rows; recent-query chips preserve text as typed; loading, empty, and recoverable error states
History (08): TV-filtered events, date grouping, clear with confirmation, navigate to file
Covered from the Files line: root and nested browsing on the shared FilesBrowserController, LazyColumn rows with stable keys, cursor paging, Refresh and Sort (centred M3 choice dialog, persisted to the account), watched progress, folder/media/unsupported-type branching with the 06b screen, Back popping the folder stack, and per-session D-pad focus memory across folders, destinations, and the rail. The playback hook is a no-op until #34; the long-press action menu is deferred to the same slice as Trash.
Search (07–07c) landed in #167 as d0e53cf: system-IME pill field (Center summons Gboard TV, no app-drawn keys, no mic), recent-query chips replayed as typed with long-press removal, cursor-paged results in the standard rows, result opens in Files, loading / no-results / failed states. The recent-search store and the search 401 helper moved to main; one TvSession per signed-in session now owns Files and Search together.
Emulator proof on the PR: idle, IME over results, results, chip focus, row focus, drawer round-trip, open in Files, no results, chip removal, chip replay, and a 40 s recording. The failed-search state could not be reproduced live: the TV emulator's Ethernet ignores airplane mode, a dead proxy, and a dead private-DNS host. Robolectric covers it.
Remaining here: long-press action menu on Files rows, History (08), Trash (13), Account/settings (09–12, 14), and the two missing oracle captures.
History (08) landed in #168 as 01ef038: a real drawer destination on the shared HistoryController, owned by TvSession with Files and Search. Title with a Clear button, events under Today / Yesterday / Last week / Last month / Earlier in the standard rows, Center on an event that names a file opens its folder in Files, Clear through a centred confirmation with stacked buttons. The account's history_enabled setting drives the disabled state.
Found on the way: the Kotlin SDK decoded every history event as an unknown type (uppercase constants against lowercase wire values), so no row could open on either surface. Fixed in putio-sdk-kotlin#51 as d9a2965; transfers and shared files now resolve. Upload events still map to a non-navigable "Activity" on both surfaces.
Emulator proof on the PR: list, clear dialog, drawer round-trip, last row, open in Files, and a recording. Not proven live: empty, disabled, failed, and paging states (the proof account has one page and history on, and clearing it would erase shared fixture state); Robolectric covers them.
Remaining here: long-press action menu on Files rows, Trash (13), Account/settings (09–12, 14), and the two missing oracle captures.
Trash (13) landed in #169 as b73f17c: Account gains a Manage your trash row (Sign out stays last) that opens Trash on the shared TrashController; Back returns to the row. Rows show size, deleted and expiry dates; Center offers Restore or Delete permanently; Restore all and Empty trash sit in the header; every mutation confirms in a centred stacked-button dialog and reports above the list with Check status or Check trash until the fresh listing settles it. Restores invalidate the Files cache and Files reloads a stale folder when it shows again. The empty state carries the oracle's 14-day copy.
Emulator proof on the PR: Account row, list, item dialog, restore and Empty confirmations (cancelled), and a recording. Not proven live: submitting any mutation and its outcome and Check flows, since Trash holds shared fixture state; Robolectric covers them.
Remaining here: long-press action menu on Files rows, Account/settings (09–12, 14, which will also give Trash its oracle entry point under Storage settings), and the two missing oracle captures.
Account/settings (09–12, 14) shipped in #170, merged as f344fa8.
Identity and quota header (avatar, username, “X of Y free” bar, Sign out button), Playback settings (Choose your proxy picker on /tunnel/routes, Remember current place, Video playback type picker on this app's /config, Autoplay next video, Show subtitles, Do not select subtitles by default), Storage settings (Move deleted files to trash with confirmation, Manage your trash with its size, Keep account history), App and device information with a Diagnostics dialog, Sign out as the final row.
Runs on the shared AccountSettingsController and AndroidAppConfigController inside the TV session; a 401 from either, or from the route list, rejects the session; the History pane follows confirmed settings values.
Failed saves show under their row and Try again hands focus back to it; every dialog returns focus to the row that opened it, also across recreation; App/Device/OS are facts outside the D-pad chain.
Video playback buffer size stays out: no server key (per the Settings rollout notes).
Live proof on the API 36 TV emulator: real account values, HLS → MP4 → HLS on /config, resume switch true → false → true read back through the API, proxy picker with the account's routes, Turn off trash? cancelled, Manage your trash round trip, Diagnostics dialog. Captures on the PR.
Remaining in this issue: Files long-press action menu, and the two missing oracle captures (conversion-in-progress, long-press menu).
Long-press Center or the Menu key on a row opens the oracle's files-actions dialog: Open in VLC (original /files/{id}/stream URL handed to org.videolan.vlc), Mark as watched / unwatched (only while the account's confirmed use_start_from is on; marking watched needs a known duration), Move to trash / Delete permanently per the confirmed trash_enabled, confirmed first with Cancel focused and run on the shared FilesBrowserEvent.Delete.
The pane shows the delete operation's phases above the rows, Check status or Retry on failure, and the fresh listing's verdict; every dialog returns focus to its row.
Shared additions: FilesWatchedRepository and FilesStreamUrls in main; never-played media keeps its duration so it can be marked watched.
Live proof on the API 36 TV emulator: menu on a video row; Mark as watched wrote the 10 s duration (read back through files.getStartFrom) and the row read 100% watched; Mark as unwatched read back 0; Move to trash on a fixture text file confirmed, reported “no longer in Files”, and trash.list shows it. The VLC handoff itself is unproven: the emulator has no VLC, so only the not-installed path was exercised. Captures on the PR.
Remaining in this issue: the two oracle captures (conversion-in-progress needs playback; long-press menu is now captured natively on #171).
Closing: all five browse slices shipped (#165–#171) with emulator proof and captures. The one oracle state not covered here, files-conversion (conversion-in-progress), is a playback interstitial and is tracked in #34. Fire TV physical proof stays under #51.
Activity
feat(tv): browse Files on the shared controller (#166)
altaywtf commentedon Sep 10, 2026
Files browse shipped in #166 as a479a2d.
Covered from the Files line: root and nested browsing on the shared
FilesBrowserController, LazyColumn rows with stable keys, cursor paging, Refresh and Sort (centred M3 choice dialog, persisted to the account), watched progress, folder/media/unsupported-type branching with the06bscreen, Back popping the folder stack, and per-session D-pad focus memory across folders, destinations, and the rail. The playback hook is a no-op until #34; the long-press action menu is deferred to the same slice as Trash.Evidence: root, nested with watched row, sort dialog, unsupported, Back restores focus, recording.
Next slices: Search (
07), History (08), Trash (13), Account/settings (09–12,14).altaywtf commentedon Sep 10, 2026
Search (
07–07c) landed in #167 as d0e53cf: system-IME pill field (Center summons Gboard TV, no app-drawn keys, no mic), recent-query chips replayed as typed with long-press removal, cursor-paged results in the standard rows, result opens in Files, loading / no-results / failed states. The recent-search store and the search 401 helper moved tomain; oneTvSessionper signed-in session now owns Files and Search together.Emulator proof on the PR: idle, IME over results, results, chip focus, row focus, drawer round-trip, open in Files, no results, chip removal, chip replay, and a 40 s recording. The failed-search state could not be reproduced live: the TV emulator's Ethernet ignores airplane mode, a dead proxy, and a dead private-DNS host. Robolectric covers it.
Remaining here: long-press action menu on Files rows, History (
08), Trash (13), Account/settings (09–12,14), and the two missing oracle captures.altaywtf commentedon Sep 12, 2026
History (
08) landed in #168 as 01ef038: a real drawer destination on the sharedHistoryController, owned byTvSessionwith Files and Search. Title with a Clear button, events under Today / Yesterday / Last week / Last month / Earlier in the standard rows, Center on an event that names a file opens its folder in Files, Clear through a centred confirmation with stacked buttons. The account'shistory_enabledsetting drives the disabled state.Found on the way: the Kotlin SDK decoded every history event as an unknown type (uppercase constants against lowercase wire values), so no row could open on either surface. Fixed in putio-sdk-kotlin#51 as d9a2965; transfers and shared files now resolve. Upload events still map to a non-navigable "Activity" on both surfaces.
Emulator proof on the PR: list, clear dialog, drawer round-trip, last row, open in Files, and a recording. Not proven live: empty, disabled, failed, and paging states (the proof account has one page and history on, and clearing it would erase shared fixture state); Robolectric covers them.
Remaining here: long-press action menu on Files rows, Trash (
13), Account/settings (09–12,14), and the two missing oracle captures.altaywtf commentedon Sep 12, 2026
Trash (
13) landed in #169 as b73f17c: Account gains a Manage your trash row (Sign out stays last) that opens Trash on the sharedTrashController; Back returns to the row. Rows show size, deleted and expiry dates; Center offers Restore or Delete permanently; Restore all and Empty trash sit in the header; every mutation confirms in a centred stacked-button dialog and reports above the list with Check status or Check trash until the fresh listing settles it. Restores invalidate the Files cache and Files reloads a stale folder when it shows again. The empty state carries the oracle's 14-day copy.Emulator proof on the PR: Account row, list, item dialog, restore and Empty confirmations (cancelled), and a recording. Not proven live: submitting any mutation and its outcome and Check flows, since Trash holds shared fixture state; Robolectric covers them.
Remaining here: long-press action menu on Files rows, Account/settings (
09–12,14, which will also give Trash its oracle entry point under Storage settings), and the two missing oracle captures.altaywtf commentedon Sep 12, 2026
Account/settings (
09–12,14) shipped in #170, merged as f344fa8./tunnel/routes, Remember current place, Video playback type picker on this app's/config, Autoplay next video, Show subtitles, Do not select subtitles by default), Storage settings (Move deleted files to trash with confirmation, Manage your trash with its size, Keep account history), App and device information with a Diagnostics dialog, Sign out as the final row.AccountSettingsControllerandAndroidAppConfigControllerinside the TV session; a 401 from either, or from the route list, rejects the session; the History pane follows confirmed settings values./config, resume switch true → false → true read back through the API, proxy picker with the account's routes, Turn off trash? cancelled, Manage your trash round trip, Diagnostics dialog. Captures on the PR.Remaining in this issue: Files long-press action menu, and the two missing oracle captures (conversion-in-progress, long-press menu).
altaywtf commentedon Sep 12, 2026
Files long-press action menu shipped in #171, merged as bbf346a (SDK: putdotio/putio-sdk-kotlin#52, 2c61413).
/files/{id}/streamURL handed toorg.videolan.vlc), Mark as watched / unwatched (only while the account's confirmeduse_start_fromis on; marking watched needs a known duration), Move to trash / Delete permanently per the confirmedtrash_enabled, confirmed first with Cancel focused and run on the sharedFilesBrowserEvent.Delete.FilesWatchedRepositoryandFilesStreamUrlsin main; never-played media keeps its duration so it can be marked watched.files.getStartFrom) and the row read 100% watched; Mark as unwatched read back 0; Move to trash on a fixture text file confirmed, reported “no longer in Files”, andtrash.listshows it. The VLC handoff itself is unproven: the emulator has no VLC, so only the not-installed path was exercised. Captures on the PR.Remaining in this issue: the two oracle captures (conversion-in-progress needs playback; long-press menu is now captured natively on #171).
altaywtf commentedon Sep 12, 2026
Closing: all five browse slices shipped (#165–#171) with emulator proof and captures. The one oracle state not covered here,
files-conversion(conversion-in-progress), is a playback interstitial and is tracked in #34. Fire TV physical proof stays under #51.