Solo: no idle unready, no party corner in fullscreen; a cancelled Invite returns to solo
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
0115d54ab8
commit
059b7dd306
4 files changed
+38
-4
No files matched your search
@@ -97,6 +97,7 @@ class ConnectFlow extends ChangeNotifier {
|
|||||||
_notify();
|
_notify();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
final fromSolo = mode == ConnectMode.host && _session.solo.value;
|
||||||
try {
|
try {
|
||||||
if (mode == ConnectMode.host) {
|
if (mode == ConnectMode.host) {
|
||||||
await _session.host(params, form);
|
await _session.host(params, form);
|
||||||
@@ -111,10 +112,14 @@ class ConnectFlow extends ChangeNotifier {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (myAttempt != _attempt) {
|
if (myAttempt != _attempt) {
|
||||||
// Cancelled after it got through: back out.
|
// Cancelled after it got through: back out (an Invite: back to solo).
|
||||||
try {
|
try {
|
||||||
|
if (fromSolo) {
|
||||||
|
await _session.cancelInvite();
|
||||||
|
} else {
|
||||||
await _session.leave();
|
await _session.leave();
|
||||||
await _session.stopServer();
|
await _session.stopServer();
|
||||||
|
}
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -240,6 +240,9 @@ class SessionCoordinator {
|
|||||||
StreamSubscription? _statusSub;
|
StreamSubscription? _statusSub;
|
||||||
|
|
||||||
bool _manualClose = false;
|
bool _manualClose = false;
|
||||||
|
/// A solo session (set by SessionState): no idle unready / sit out,
|
||||||
|
/// there is nobody to hold up.
|
||||||
|
bool solo = false;
|
||||||
bool _playerReady = false;
|
bool _playerReady = false;
|
||||||
bool _wasPlayAllowed = false;
|
bool _wasPlayAllowed = false;
|
||||||
// Last ready flag the server reported for self; restored after a
|
// Last ready flag the server reported for self; restored after a
|
||||||
@@ -949,7 +952,9 @@ class SessionCoordinator {
|
|||||||
// activity so a pause after a long watch starts a fresh idle clock.
|
// activity so a pause after a long watch starts a fresh idle clock.
|
||||||
if (r != null) _readyAfterJoinBack(r, now);
|
if (r != null) _readyAfterJoinBack(r, now);
|
||||||
final sitOutWhenIdle = AppSettings.instance.idleSitsOut.peek();
|
final sitOutWhenIdle = AppSettings.instance.idleSitsOut.peek();
|
||||||
final event = _idle.tick(now,
|
final event = solo
|
||||||
|
? IdleEvent.none
|
||||||
|
: _idle.tick(now,
|
||||||
playing: serverState.peek()?.transport == 'playing',
|
playing: serverState.peek()?.transport == 'playing',
|
||||||
selfReady: selfMember.peek()?.ready ?? false);
|
selfReady: selfMember.peek()?.ready ?? false);
|
||||||
switch (event) {
|
switch (event) {
|
||||||
|
|||||||
@@ -296,7 +296,7 @@ class _SessionPlayerState extends State<SessionPlayer> {
|
|||||||
_status(),
|
_status(),
|
||||||
_progressLine(),
|
_progressLine(),
|
||||||
_jellyfinOverlay(),
|
_jellyfinOverlay(),
|
||||||
if (widget.fullscreen) ...[_pausedParty(), _unreadChip()],
|
if (widget.fullscreen) ...[if (!SessionState.instance.solo.value) _pausedParty(), _unreadChip()],
|
||||||
] else
|
] else
|
||||||
_miniOverlay(),
|
_miniOverlay(),
|
||||||
// Sitting out: nothing is loaded; the card covers the
|
// Sitting out: nothing is loaded; the card covers the
|
||||||
|
|||||||
@@ -260,12 +260,13 @@ class SessionState {
|
|||||||
/// pick, seeked to where it was; if hosting fails, solo comes back.
|
/// pick, seeked to where it was; if hosting fails, solo comes back.
|
||||||
Future<void> host(ConnectParams params, ConnectForm form) async {
|
Future<void> host(ConnectParams params, ConnectForm form) async {
|
||||||
if (!solo.peek()) return _host(params, form: form);
|
if (!solo.peek()) return _host(params, form: form);
|
||||||
final carry = _carry();
|
final carry = _invited = _carry();
|
||||||
switching.value = true;
|
switching.value = true;
|
||||||
try {
|
try {
|
||||||
await coordinator.leave();
|
await coordinator.leave();
|
||||||
await stopServer();
|
await stopServer();
|
||||||
solo.value = false;
|
solo.value = false;
|
||||||
|
coordinator.solo = false;
|
||||||
try {
|
try {
|
||||||
await _host(params, form: form);
|
await _host(params, form: form);
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
@@ -289,6 +290,27 @@ class SessionState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// What an Invite from solo carried over, for [cancelInvite].
|
||||||
|
({PickedMedia pick, double position})? _invited;
|
||||||
|
|
||||||
|
/// Invite cancelled after the hosted server already came up: back to
|
||||||
|
/// solo with the same media, not out of the session.
|
||||||
|
Future<void> cancelInvite() async {
|
||||||
|
final carry = _invited;
|
||||||
|
switching.value = true;
|
||||||
|
try {
|
||||||
|
await coordinator.leave();
|
||||||
|
await stopServer();
|
||||||
|
await _host(_soloParams!, soloSession: true);
|
||||||
|
if (carry != null) await _resume(carry);
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint('back to solo failed: $e');
|
||||||
|
await leave();
|
||||||
|
} finally {
|
||||||
|
switching.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Watch alone: the same hosted path, on 127.0.0.1 and a free port, no
|
/// Watch alone: the same hosted path, on 127.0.0.1 and a free port, no
|
||||||
/// password, nothing put up yet. Nobody else can reach it.
|
/// password, nothing put up yet. Nobody else can reach it.
|
||||||
Future<void> startSolo(ConnectParams params) async {
|
Future<void> startSolo(ConnectParams params) async {
|
||||||
@@ -394,6 +416,7 @@ class SessionState {
|
|||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
solo.value = soloSession;
|
solo.value = soloSession;
|
||||||
|
coordinator.solo = soloSession;
|
||||||
route.value = AppRoute.session;
|
route.value = AppRoute.session;
|
||||||
} finally {
|
} finally {
|
||||||
if (form != null) await _saveFormQuietly();
|
if (form != null) await _saveFormQuietly();
|
||||||
@@ -478,6 +501,7 @@ class SessionState {
|
|||||||
await coordinator.leave();
|
await coordinator.leave();
|
||||||
await stopServer();
|
await stopServer();
|
||||||
solo.value = false;
|
solo.value = false;
|
||||||
|
coordinator.solo = false;
|
||||||
serverLabel.value = '';
|
serverLabel.value = '';
|
||||||
status.value = const HealthStatus(HealthSeverity.info, 'idle');
|
status.value = const HealthStatus(HealthSeverity.info, 'idle');
|
||||||
route.value = AppRoute.home;
|
route.value = AppRoute.home;
|
||||||
|
|||||||
Reference in new issue
Block a user