mirror of
https://github.com/narrrl/proton-stream.git
synced 2026-11-03 16:41:26 +01:00
171 lines
8.3 KiB
Markdown
171 lines
8.3 KiB
Markdown
# Android plan
|
||
|
||
Where the Android client stands against the desktop app, and what to change to
|
||
make it feel like a modern streaming app rather than a settings form with a
|
||
player attached. Written 2026-10-03 from a source review and four screenshots
|
||
(Library, Title, Shares, Settings) taken on a phone running v0.5.0.
|
||
|
||
Android last caught up with the desktop on 2026-08-10 (`4ef6225`); the desktop
|
||
gained about twenty features on 2026-10-02 that Android does not have.
|
||
|
||
## Status (2026-10-03)
|
||
|
||
Done: section 0, every parity item, and every recommendation in section 2 —
|
||
the Library, Title, Shares, Settings and Downloads redesigns, per-page app
|
||
bars drawn edge to edge, search behind an icon, skeleton loading and
|
||
generated placeholder art, Settings sub-pages and a language picker, a
|
||
long-press Change match, Inter, light and tablet screenshots, the library
|
||
and a title side by side from 840 dp, a poster-to-backdrop shared element
|
||
transition, and predictive back on the title page.
|
||
|
||
Two departures from the text below. The tablet layout is a two-pane `Row`
|
||
rather than `ListDetailPaneScaffold`, which would have added the
|
||
`adaptive-layout` artifact for one split. Pull to refresh shows the
|
||
indicator while a crawl runs, but not the crawl's progress.
|
||
|
||
Not yet verified on a device; the host gate (ktlint, unit and screenshot
|
||
tests) passes, and Android lint runs in CI.
|
||
|
||
## 0. CI (done)
|
||
|
||
Every `Android` workflow run since August failed in `:app:buildRustHost`:
|
||
`pstr-core` pulls `keyring` → `dbus-secret-service` → `libdbus-sys`, which needs
|
||
`libdbus-1-dev` on the host. Because no run ever succeeded, no cache was ever
|
||
saved, so each run started from nothing.
|
||
|
||
- `libdbus-1-dev` added to both jobs' apt install.
|
||
- `Swatinem/rust-cache` shares one key between the two jobs and saves on failure.
|
||
- `android/app/build/generated/mpv` is cached on the hash of
|
||
`scripts/build-libmpv-android.sh`; the script writes a `STAMP` (revision plus
|
||
its own hash) last and skips the whole libmpv build when the stamp matches.
|
||
|
||
Later runs also needed meson 1.12.1 from PyPI (noble's 1.3.2 is too old for
|
||
the pinned fontconfig), libmpv built and cached in its own steps so a later
|
||
failure keeps it, and lint's `OldTargetApi` made informational. A cached run
|
||
restores libmpv in under a minute.
|
||
|
||
## 1. Desktop parity
|
||
|
||
Ordered by value on a phone.
|
||
|
||
1. **Open share links from outside the app.** The manifest has only the
|
||
launcher intent. Add an `ACTION_VIEW` filter for `drive.proton.me/urls/*` and
|
||
an `ACTION_SEND` (`text/plain`) filter; both open the add-share dialog with
|
||
the link filled in. Desktop: `4a54af3`, `53a1d0a`.
|
||
2. **Streaming cache budget.** Android runs on the fixed 4 GiB default
|
||
(`DiskCacheConfig::DEFAULT_BUDGET_BYTES`), large for a phone. Expose
|
||
`DiskCache::set_budget` through `pstr-android`, add a 1–16 GiB choice with a
|
||
usage readout under Storage. Desktop: `a432a93`.
|
||
3. **Hardware-decoding switch.** `pstr_mpv.cpp` hard-codes
|
||
`hwdec=auto-copy-safe`; a device with green frames has no way out. A
|
||
Settings toggle, applied from the next file.
|
||
4. **Episode list in the player.** A bottom sheet (portrait) or side panel
|
||
(landscape) with the title's episodes, opened on the playing season and
|
||
scrolled to the playing episode. Desktop: `7e734db`.
|
||
5. **Long-press menu on tiles.** Play/resume, mark watched or unwatched,
|
||
download, change match, remove from Continue watching, in a
|
||
`ModalBottomSheet`. Desktop: `c5808a5`.
|
||
6. **Undo on snackbars** for marking a title and leaving Continue watching.
|
||
`AppUiState.message` is a bare string today; it needs an action. Desktop:
|
||
`79c3f68`.
|
||
7. **History tab.** Needs a bridge call over the `pstr-core::library` query
|
||
the desktop page uses. Desktop: `e7eeaa5`.
|
||
8. **Buffered range on the seek bar** from mpv's `demuxer-cache-time`.
|
||
9. **Up-next card** with the next episode's still and a countdown ring instead
|
||
of "Up next in 7s" text.
|
||
10. **Featured banner** at the top of the library. Desktop: `7d03736`.
|
||
11. **Bundled Inter** in `ui/theme/Type.kt`, so both clients read the same.
|
||
Desktop: `558446b`.
|
||
|
||
## 2. UI recommendations
|
||
|
||
### Everywhere
|
||
|
||
- **Colours stay the theme's.** The red is the Persona theme's accent and the
|
||
card tint comes from the shared palette, so the redesign changes layout and
|
||
button hierarchy, not colours.
|
||
- **One button hierarchy.** At most one filled accent button per screen;
|
||
secondary actions tonal or outlined; destructive actions behind a menu and a
|
||
confirmation, never a filled red button in a list row.
|
||
- **Edge-to-edge, per-screen titles.** The "proton-stream" app bar on every
|
||
page wastes a band of height. Library uses a collapsing large title; Title
|
||
pages draw the backdrop under the status bar; other tabs use their name.
|
||
- **Skeletons instead of spinners** for library and title loading, and
|
||
generated placeholder art (gradient from the accent plus the title's
|
||
initials) instead of a black card with a play triangle (Akira).
|
||
- **Pull-to-refresh** (`PullToRefreshBox`) replaces the top-bar refresh icon,
|
||
with crawl progress shown in the indicator area.
|
||
- **Split `ui/ProtonStreamApp.kt`** (1665 lines) into one file per screen
|
||
before the work below; every item touches it.
|
||
|
||
### Library
|
||
|
||
- Poster grid (2:3, `posterUrl`) at three columns on a phone, title under the
|
||
poster with no card body. The current 210 dp cropped backdrops fit two titles
|
||
per screen.
|
||
- Continue watching: 16:9 still with the progress bar laid over the bottom
|
||
edge of the image and "S03E11 · 12 min left" under it.
|
||
- Search becomes an icon in the app bar that expands into an M3 `SearchBar`,
|
||
instead of a permanent field above everything.
|
||
- Fix "1 episodes" (line ~507; the season header already pluralises).
|
||
|
||
### Title page
|
||
|
||
- Full-bleed backdrop with a gradient scrim, poster, title and meta chips
|
||
(year, score, genres) over it, collapsing as the page scrolls.
|
||
- Synopsis clamped to three lines with "More".
|
||
- One full-width primary button, "Resume S03E11" or "Play S01E01", then a row
|
||
of icon actions: download, mark watched, and a ⋮ menu holding Start over,
|
||
Change match and More on AniList. Today five buttons of three styles wrap
|
||
over three lines.
|
||
- Drop the "Preferred tracks" form and its Save button from this page. The
|
||
player already remembers tracks by name per title (`d3c5f07`); expose any
|
||
override from the player's track chooser.
|
||
- Season picker as a dropdown chip or tabs, not stacked accordions; a 40
|
||
episode title is one long scroll today.
|
||
- Episode rows: 16:9 still with progress overlay, "1 · Mother and Children"
|
||
(provider name, else "Episode 1") rather than the raw file name
|
||
`[Judas] Oshi no Ko - S01E01.mkv`, runtime or air date as supporting text,
|
||
watched and download state as small trailing icons. The red `S01E01` label
|
||
above each row goes.
|
||
|
||
### Shares
|
||
|
||
- `ListItem` rows: name, "12 titles · crawled 2 h ago" or the failure, and a ⋮
|
||
menu with Refresh, Re-enter link and Remove (confirmed). The current row
|
||
wraps "Custom password stored securely" over three lines beside three
|
||
differently styled actions.
|
||
- "Add share" as an extended FAB, which is also where the share-link intent
|
||
from parity item 1 lands.
|
||
|
||
### Settings
|
||
|
||
- Grouped `ListItem` rows (headline, one line of supporting text, trailing
|
||
switch), with the long explanations moved into the supporting line or an
|
||
info dialog. Today each toggle carries a paragraph.
|
||
- Split into sub-pages once storage and decoding settings land: Playback,
|
||
Downloads & storage, Appearance, Metadata, About.
|
||
- Language fields become a picker dialog over a language list, not free text.
|
||
- Storage shows a usage bar (cache, offline episodes) above the budget choice.
|
||
|
||
### Robustness
|
||
|
||
- Screenshot tests (Roborazzi, JVM, no device) for each screen in light and
|
||
dark, phone and tablet, at font scale 1.0 and 1.5 — the redesign changes
|
||
every screen, and `docs/TESTING.md` has no visual layer today.
|
||
- 48 dp minimum touch targets and content descriptions on the new icon-only
|
||
actions.
|
||
- Tablet: `ListDetailPaneScaffold` for library + title, since
|
||
`NavigationSuiteScaffold` already switches to a rail there.
|
||
- Shared-element transition from a poster to its title page, and predictive
|
||
back.
|
||
|
||
## Suggested order
|
||
|
||
1. CI green (section 0).
|
||
2. Split `ProtonStreamApp.kt`; add screenshot tests for the current screens.
|
||
3. Parity 1–3 (small, phone-specific fixes).
|
||
4. Button hierarchy and Inter — every later screen inherits them.
|
||
5. Title page, then Library, then Shares and Settings.
|
||
6. Parity 4–10.
|