0.2.98
This commit is contained in:
@@ -708,7 +708,9 @@ of a copy, wrong the moment Tracearr corrects a session. It is read two ways:
|
||||
about a title somebody abandoned, and a feed carrying those is one nobody opens.
|
||||
|
||||
**Search** (`ui/search/`) is a two-pane instant-search destination on the rail: a fixed
|
||||
6×6 on-screen keyboard on the left, a results grid on the right that updates as you type.
|
||||
6×6 on-screen keyboard on the left, with `SearchGenres` above `SearchResults` on the right.
|
||||
The results list updates as you type and uses the same shared `MediaResultCard` presentation
|
||||
as My Requests; request status and actions remain feature-owned slots around that shared row.
|
||||
Nothing is ever "submitted". `SearchViewModel` runs one pipeline — `debounce(250)` →
|
||||
`trim` → `distinctUntilChanged` → `collectLatest { repository.search(it) }` — and
|
||||
`collectLatest` is the load-bearing part: it cancels the in-flight request, so a slow
|
||||
@@ -785,17 +787,17 @@ at a time. Things to preserve:
|
||||
the server is the same judgement from the other side, for an Emby that did not count.
|
||||
- **A page is appended by its own offset**, never by order of arrival: a response for an
|
||||
offset already scrolled past, or for a genre the viewer has left, is dropped rather than
|
||||
pasted into the middle of the grid. A page that fails part way down keeps what is on
|
||||
pasted into the middle of the list. A page that fails part way down keeps what is on
|
||||
screen and simply stops paging.
|
||||
- **The scroll trigger is a `snapshotFlow`, not a composable read.** The last visible index
|
||||
changes on every frame of a scroll, and reading it in the body would recompose the grid
|
||||
changes on every frame of a scroll, and reading it in the body would recompose the list
|
||||
the whole way down a genre — the same rule as the animation one above. It asks
|
||||
`LOAD_MORE_ROWS_AHEAD` rows early, since a request that starts when the viewer arrives at
|
||||
several items early, since a request that starts when the viewer arrives at
|
||||
the end is one they watch.
|
||||
- **Something has to take the focus the chip was holding**, because opening a shelf unmounts
|
||||
the whole discovery pane. The grid claims it when the first page lands, and an empty or
|
||||
failed genre hands it back to the keyboard rather than leaving a television with nothing
|
||||
focused.
|
||||
- **Genre and result focus targets are separate.** The genre strip stays mounted above the
|
||||
results; a genre result claims its own requester when the first page lands, Back restores
|
||||
the strip, and an empty or failed genre hands focus back deterministically rather than
|
||||
leaving a television with nothing focused.
|
||||
- **Episodes are excluded on both paths.** An episode inherits its series' genres, so
|
||||
including them fills a page with twenty entries of one comedy and buries the rest.
|
||||
- **Movies and TV Series have their own full-width genre browser.** A fixed row of colourful
|
||||
@@ -862,9 +864,9 @@ at a time. Things to preserve:
|
||||
missing the route, and search results pasted onto the end of a genre would be nonsense.
|
||||
|
||||
Focus is the hard part and is explicit: the leftmost keyboard column goes to the rail, the
|
||||
rightmost goes to the results grid, the grid's first column goes back to the *last key
|
||||
used* (a `FocusRequester` attached to whichever key that is), and the grid has a
|
||||
`focusRestorer`. Back moves results → keyboard → genre → leave, one step per press.
|
||||
rightmost goes to Genres, Down enters Search Results, and every result goes back to the
|
||||
*last key used* (a `FocusRequester` attached to whichever key that is). Back closes an open
|
||||
genre shelf before moving results → keyboard → leave, one step per press.
|
||||
Physical keyboards and phone-remote apps feed the same state through one
|
||||
`onPreviewKeyEvent` that consumes only printable characters and backspace — D-pad and Back
|
||||
must fall through. The voice button needs the `android.speech.RecognitionService` entry in
|
||||
|
||||
Reference in New Issue
Block a user