Protocol 10 presence gate, drop/paste anywhere, quick UI fixes

Ready gate: whoever is in the server while it is not playing counts (joining
while playing does not pause anyone); a swap counts everyone present and
keeps ready flags; the quorum rule is gone. Optional 'Unready when the
video changes'. No 'Skip 1:30' guess when the media has chapters.

Drag & drop and Ctrl+V anywhere (fox_utils): files, folders and links get a
small card asking how to open them. Files series start collapsed.

UI: Tab never moves focus and Space is always ready outside text fields;
chat focuses its field; unread badge on uosc and a chip in fullscreen;
people-only chat with an Activity toggle; skip pills show 5 s then with
the controls; volume up to 150%; own avatar same size as the party.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
foxyzandClaude Opus 5.5 committed 2026-10-09 07:06:48 +03:00
1 parent 5f22be6c20
commit 8effa573a0
38 files changed
+1529 -303

No files matched your search

+11 -2
View File
@@ -111,8 +111,14 @@ void main() {
group('skip offers', () {
final op = SkipRange(s(30), m(2), SkipSource.chapter);
final ed = SkipRange(m(20), m(21, 30), SkipSource.chapter);
SkipOffer? at(Duration p, {SkipRange? opening, SkipRange? ending, Duration? duration}) => skipOfferAt(
position: p, duration: duration ?? m(24), opening: opening, ending: ending);
SkipOffer? at(Duration p,
{SkipRange? opening, SkipRange? ending, Duration? duration, bool chaptered = false}) =>
skipOfferAt(
position: p,
duration: duration ?? m(24),
opening: opening,
ending: ending,
chaptered: chaptered);
test('Skip OP inside the opening, to its end', () {
expect(at(s(29), opening: op, ending: ed), isNull);
@@ -141,6 +147,9 @@ void main() {
expect(at(m(1), ending: ed), SkipOffer(SkipKind.fixed, m(2, 30)));
// An opening known (but not playing) means no fallback.
expect(at(m(3), opening: op), isNull);
// Chapters without an OP chapter: no opening on purpose.
expect(at(m(1), chaptered: true), isNull);
expect(at(m(20, 10), ending: ed, chaptered: true), SkipOffer(SkipKind.ending, m(21, 30)));
});
});