Desktop: video freeze recovery, session fixes, Home redesign

- Player + VideoController per session; Reload video (Ctrl+R) and a
  frozen-picture watchdog that reloads automatically.
- Shortcuts no longer fire while typing; empty swap disabled;
  hwdec setting/env actually applied.
- Idle unready measured from real inactivity; cancellable reconnects
  and setup; ready restored from server state; kicked/failed host
  stops its server; graceful leave on window close; no URLs with
  keys in display names.
- Welcome + connect screens replaced by one Home screen with Join and
  Host cards, recent servers, Settings, Integrations and About.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
foxyzandClaude Opus 5.5 committed 2026-10-07 00:41:02 +03:00
1 parent beae87b0cc
commit aeff087c7d
30 files changed
+3278 -601

No files matched your search

+43
View File
@@ -0,0 +1,43 @@
enum IdleEvent { none, warn, unready }
/// Idle auto-unready clock. Idle time counts from the later of the user's
/// last input and the last moment playback was running: watching is
/// activity, so a long watch followed by a pause starts a fresh 10 min.
/// The unready also always trails its warning by the full grace period.
class IdleTracker {
static const warnAfter = Duration(minutes: 8);
static const unreadyAfter = Duration(minutes: 10);
DateTime _lastActive;
DateTime? _warnedAt;
IdleTracker(DateTime now) : _lastActive = now;
void activity(DateTime now) {
_lastActive = now;
_warnedAt = null;
}
/// Called once per tick. Warn and unready only matter while self is
/// ready; while the room plays the ready flag gates nothing.
IdleEvent tick(DateTime now, {required bool playing, required bool selfReady}) {
if (playing) {
activity(now);
return IdleEvent.none;
}
if (!selfReady) return IdleEvent.none;
final warnedAt = _warnedAt;
if (warnedAt != null) {
if (now.difference(warnedAt) >= unreadyAfter - warnAfter) {
activity(now);
return IdleEvent.unready;
}
return IdleEvent.none;
}
if (now.difference(_lastActive) >= warnAfter) {
_warnedAt = now;
return IdleEvent.warn;
}
return IdleEvent.none;
}
}