Skip to content

Watch party: host controls, friend invites, chat history, better sync - #67

Closed
professorDeveloper wants to merge 1 commit into
next/3.3.0from
feat/watch-party-plus
Closed

professorDeveloper wants to merge 1 commit into
next/3.3.0from
feat/watch-party-plus

Conversation

@professorDeveloper

Copy link
Copy Markdown
Owner

App side of the Watch Party round. It needs professorDeveloper/sozo-backend#80 for the new features. Against a server without that PR the app behaves as before: no history, no pong so no clock offset, and the new settings, kick and transfer events are ignored by the server.

What changes

Lobby (host)

  • A settings card with:
    • room size (2 up to the server's limit);
    • "Only host controls playback";
    • "Lock room";
    • "Wait for everyone".
  • Every change goes out as party:settings and comes back to everyone, so the room stays the only state.
  • An Invite friends button opens a sheet that lists accepted friends from /api/social/friends. Sozo's social graph is mutual friends, not follows, so "people you follow or who follow you" maps to this list.
    • Tapping a friend calls the existing invite endpoint, which was never called before.
    • Each row shows its own cooldown countdown, seeded from the new GET /:code/invites and from 429 responses.
  • Member bar: as host, tap, long-press or D-pad-select another member to get Make host or Remove from party (with a confirm step). Members who are buffering get a small spinner badge.

Chat

  • The panel now reads WatchPartyService.chatLog: history from party:state first, then live lines. Joiners and reconnecting users see what was said.
  • System lines render as small italic rows: "X joined", "X left", "X is now the host", "X was removed".
  • Lines from blocked users are filtered by the server.

Sync

  • PartyClock estimates the server clock offset from party:ping/party:pong, keeping the fastest of the last 8 round trips.
    • Each sync's receipt time is re-based to the local instant the server meant, so a guest on a slow link no longer trails the host by the one-way trip.
    • It falls back to the old receipt-time behaviour when there is no offset or the shift looks wrong.
    • The drift rules and the applyingRemote loop guard are unchanged.
  • Buffering presence: the player reports a stall on its existing 2 s drift tick, and only changes go on the wire. Loading a new episode counts as a stall; an error or a missing plugin does not.
  • Wait for everyone (PartyWaitPolicy): when a guest has buffered for more than 3 s, the host's player pauses and tells the room. It resumes when nobody is buffering, or after 15 s at most. After giving up it ignores that same stall, so it does not keep pausing.

Deferred invite

  • When a party link opens while signed out, the code is kept in PendingPartyCode (Hive, 1-hour TTL) through sign-in, sign-up or first-run setup.
  • It opens once afterwards, from goAfterAuth or Home's first frame. The two share one navigation.
  • If the user backs out of sign-in, the code is dropped.

Housekeeping

  • deeplink/apple-app-site-association now matches the live copy in sozo-web: it adds /party/*, /link/* and /pair/*.

Strings: 24 new watch_party.* keys, translated into all 16 locales.

Player files: only player_page.party.dart changed. The wait-for-all dispatch lives in the service, so player_page.dart needed no new import.

Tests

  • test/features/watch_party/party_sync_test.dart:
    • clock offset and alignment math;
    • the wait-for-everyone policy;
    • parsing of chat history and system lines;
    • invite cooldown countdown.
  • test/features/watch_party/pending_party_code_test.dart: the pending-code handoff (normalize, open once, TTL, cancel).

Not verified

  • Nothing was run locally, by the owner's rule: no flutter, dart, analyze or tests on the dev machine. CI is the first compile.
  • No device testing of:
    • the lobby UI;
    • D-pad focus on TV for the member menu and invite sheet;
    • the sign-in handoff on a fresh install;
    • wait-for-everyone in a real room.
  • Real store-install deferred deep links are not covered. On a brand-new install the link is gone once the user has gone through the store, so the code only survives if the app was installed and opened from the link. That needs a Play Install Referrer or a clipboard handoff from the web page.
  • The web fallback page (/party/:code) is not changed. It lives in the separate sozo-web repo (open/index.html), so I did not add the copy-code-to-clipboard there.

- Lobby host card: room size, host-only playback, lock room, wait for
  everyone, all live over party:settings
- Invite friends sheet on the existing invite endpoint, with per-friend
  cooldowns
- Make host / remove from party from the member bar (tap, long-press or
  D-pad), and a buffering badge per member
- Chat history from party:state plus joined/left/host/removed lines
- party:ping clock offset re-bases each sync so a slow link no longer
  trails the host by its one-way trip
- Guests report buffering; with wait for everyone on, the host holds up
  to 15 s for a guest stuck over 3 s
- A party invite opened while signed out is kept through sign-in or
  first-run setup and opens once afterwards
- apple-app-site-association now lists /party/*, /link/* and /pair/*
@professorDeveloper

Copy link
Copy Markdown
Owner Author

Combined into one PR against release/3.2.1.

@professorDeveloper
professorDeveloper deleted the feat/watch-party-plus branch November 7, 2026 13:16
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.

1 participant