forked from Foxyz/sync_replay_project
- What's next is the server's: state.advance counts down (10 s) when the media finishes with an Up next item first, holds while its performer or warm source is gone, and sets queuePlay at its end; cancel is shared, a seek or swap ends it; the server skips items nobody can put up. Shared rules in core whats_next.dart; the app's janitor, per-screen countdown and end-of-episode card are gone. - The continuation (next Jellyfin episode, next file of a local show with its gaps) is an auto item under "Continues with", prepared like Up next's first item. - Watch tracking by time In (D3): only time played while this viewer is in counts; away, paused, held, jumps and stalls never do (P7, P9). WatchTracker + device WatchHistory (files, links); Jellyfin progress reads the same watch; records are the AniList seam. - A server restart no longer loses what played: apps hold their media and one offers it back (swap.restore, first offer wins), Up next is re-added, the source re-feeds, and the watch carries on. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
28 lines
1.2 KiB
Dart
28 lines
1.2 KiB
Dart
import 'package:sync_relay_core/core.dart';
|
|
|
|
// The app's reading of presence (PROTOCOL.md "Presence"): every count,
|
|
// list and wait in the UI goes through these, on top of core's
|
|
// [PresencePolicy] and [isAlone].
|
|
|
|
/// What each presence counts for (the one table, shared with the server).
|
|
const presencePolicy = PresencePolicy();
|
|
|
|
/// Counted in "2/3 ready" and waited for by name: its presence counts for
|
|
/// the ready counter and its player can open the media.
|
|
bool countsForReady(MemberView m) => m.error.isEmpty && presencePolicy.countsFor(m.presence, Purpose.readyCounter);
|
|
|
|
/// Connected and watching (`in` or `joining`): can do things for the
|
|
/// party now (put up an Up next item; core's [isPresentMember]).
|
|
bool isPresent(MemberView m) => isPresentMember(m);
|
|
|
|
/// Nobody but [selfId] is connected in [members] (D9, core's [isAlone]).
|
|
bool aloneIn(List<MemberView> members, String selfId) =>
|
|
isAlone([for (final m in members) if (m.id != selfId) m.presence]);
|
|
|
|
/// "3 min" / "40 s": how long since [since] (a `goneSince`), at [now].
|
|
String sinceText(DateTime since, DateTime now) {
|
|
final d = now.difference(since);
|
|
if (d.inMinutes >= 1) return '${d.inMinutes} min';
|
|
return '${d.inSeconds.clamp(0, 59)} s';
|
|
}
|