Skip to content

Mob 0.9.17 (start_async), #128 fixes, skeleton-first pages, and the TMDB services catalogue (#106) - #129

Merged
shahryarjb merged 13 commits into
masterfrom
chore/mob-0.9.12
Oct 9, 2026
Merged

shahryarjb merged 13 commits into
masterfrom
chore/mob-0.9.12

Conversation

@shahryarjb

Copy link
Copy Markdown
Member

What this brings

Mob 0.9.12 and mob_dev 0.7.16; the native shell stays on mob_new 0.6.3.

#128 — report of 9 Oct

  • Share card: the card alone (its own corners and shadow on a thin page margin), sent as image/png so Telegram shows a picture; the fake scope chips are gone. K-78 capture-node in MobBridge.kt.
  • Your year: the empty dock slot is a Share button; genre hours split rather than double-counted; month and kind charts in hours; Watched most rows open their title.
  • What fits: no "0 of them" when the region has no streaming data.
  • Up next: series measured by their episodes, so runtime chips, Time left and Closest to finishing work; the whole row opens; no empty Gone cold / Ready bands.
  • Discover: a pick opens its page (Add to library there) instead of adding; ranked by language and genre; seeds on what you watch and falls back when TMDB has nothing; posters fetched in parallel; no black smudge on Picks from.
  • Film/Series: the list disc turns gold once a title is in a list. Series pushed with tracked_id: (Inbox, Notifications, What fits, Stats) now open that show.
  • Long seasons (Radio Star, 988 episodes): opens on its hero and skeleton blocks, loads the season in a task, episodes as a lazy list.

Skeleton-first pages (Kati.Screens.Later, the task-and-message pattern Mob's author recommends): Series, Film, Up next, Stats, and — measured against a real-sized library — Home, Library, What fits, Notifications, Season and Episode ratings. Pages that load in a few ms are left alone.

#106 — the services catalogue

  • Kati.Media.Tmdb.watch_provider_catalogue/1 keeps provider_id, logo and display order; Kati.Services.Catalogue keeps it 7 days (CachePolicy.catalogue_refresh_days/0) and falls back to a stale copy.
  • My services: "From TMDB" list with logos, I pay / Free; a service added from it carries its provider_id and no price. A region TMDB has no data for (Iran) says so; typed-in services still work.
  • Discover's sheet: one chip per service with an id, narrowing /discover with with_watch_providers in the reader's region.

Tested

Closes #128
Closes #106

🤖 Generated with Claude Code

shahryarjb and others added 13 commits October 7, 2026 09:48
b75ba81 made every move between the three shelves swap the page in place
(`reset_to`) instead of pushing, and wrote the rule into Books' moduledoc; the
test still asserted four pushes, so it failed on master.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
What 0.9.11 and 0.9.12 add natively — deep links and held presses on
Android — needs bridge code only for apps that use them, and Kati uses
neither yet, so the Elixir side runs on the 0.6.3 shell. mob_dev keeps the
same exact zig pin. bin/mob_bridge_diff.sh against mob_new 0.6.7 lists six
vendored files that merge would touch; native/UPSTREAM records the new pins.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…er Discover, gold list disc, fast long seasons

- Share card: K-78 captures the card node (not the screen), framed square or
  9:16, and shares it as image/png so Telegram shows a picture. The fake
  scope rail is gone.
- Your year: the empty dock slot is a Share button.
- Stats: genre hours are split, not double counted; month and kind charts in
  hours; Watched most rows open their title.
- What fits: no "0 of them" when the region has no streaming data.
- Up next: series measured by episodes so runtime chips, Time left and
  Closest to finishing work; time sorts fixed; whole row opens; no empty
  Gone cold band.
- Discover: a pick opens its page (Add to library there) instead of adding;
  ranked by language and genre; 9 picks; no black smudge on Picks from.
- Film/Series: list disc turns gold once the title is in a list.
- Series: a long season draws 30 episodes at a time; stale caches refresh
  in the background after the page opens from SQLite.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t's fold

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… show it was pushed

- Discover seeded on the newest title touched, which was one added and
  never started, and TMDB had nothing for it: the page opened empty. Seeds
  are now watching/finished first, and an empty answer tries the next title.
- Series read only :id, so Inbox, Notifications, What fits and Stats
  (which push :tracked_id) opened whatever topped the shelf.
- Up next draws no "Ready to watch · 0" over a lone hero.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d, filters close Picks from

Nine posters one after another kept the rail on "Looking for something"
for most of a minute on the phone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…argin

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…task, episodes as a lazy list

The first frame is two rows (poster, title, shelf chip); the season is read
and shaped under Kati.TaskSupervisor and sent back as {:series_loaded, ...},
the task-and-message pattern Mob's author recommends until the framework has
its own wrapper. The page is a lazy list: each episode is an item, and
reaching the end widens the window instead of waiting for Show more.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Kati.Screens.Later is the one place the task-and-message pattern lives:
run/2 sends {:kati, :loaded, {key, value}}, which Root and Pushed already
route to handle_kati/3, and blocks/1 draws the skeleton. Series moves onto
it. A re-read on the way back keeps what was drawn rather than flashing the
skeleton again. Off in the host tests (:screens_in_background).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…aint a skeleton first

Measured against a library shaped like the owner's, these six were the loads
over ~15ms on the host (Home 73ms). `later: true` on Root or Pushed paints
skeleton blocks and runs the page's own load/1 right after, in its own
process, so nothing a load does with self() changes. Pages under ~12ms stay
as they are: a one-frame skeleton is a flicker. Test leftovers from #128's
tests (a list, a status flip) are cleaned up.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ache, and Discover narrowed to your services

- Kati.Media.Tmdb.watch_provider_catalogue/1 merges /watch/providers/tv and
  /movie for a region and keeps provider_id, logo and display order.
- Kati.Services.Catalogue keeps it in Mob.State per region for
  CachePolicy.catalogue_refresh_days/0 (7), fetches the logos alongside, and
  falls back to a stale copy when the request fails.
- My services: a "From TMDB" list loaded after the first frame, I pay / Free,
  twelve at a time; a service added from it carries its provider_id and no
  price. A region TMDB has no data for (Iran) says so. Suggestions keep the
  catalogue's id too.
- Discover's sheet: one chip per service with an id; with_watch_providers,
  watch_region and flatrate|free|ads on the request, and the heading says
  "on your services".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Series, Film, Up next, Stats and My services' catalogue now load their slow
half with Mob.Socket.start_async/3 and handle_async/3 instead of Kati's own
task-and-message helper. The task belongs to the page and stops with it, a
second load of one name replaces the first, and a crash arrives as
{:exit, reason} — each page then reads in-process rather than keeping its
skeleton up. Tests await with Mob.ScreenCase.render_async/2.
Kati.Screens.Later keeps only what Mob has no equivalent for: the skeleton
blocks and first/3 for pages whose own load/1 is the slow part.

Also: Provider.upsert catches the create race between two fetches of one
title (a preview and a background refresh), and Provider.message answers a
write error with a sentence instead of a FunctionClauseError.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@shahryarjb shahryarjb changed the title Mob 0.9.12, #128 fixes, skeleton-first pages, and the TMDB services catalogue (#106) Mob 0.9.17 (start_async), #128 fixes, skeleton-first pages, and the TMDB services catalogue (#106) Oct 9, 2026
@shahryarjb
shahryarjb merged commit 12cbb15 into master Oct 9, 2026
1 check passed
@shahryarjb
shahryarjb deleted the chore/mob-0.9.12 branch October 9, 2026 18:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Report 9 Oct - Global Screen 92's service list is a fixture: take the catalogue from TMDB /watch/providers and let the reader type the price

1 participant