fix: watch together room re-join and participant discovery

close #875
This commit is contained in:
edde746
2026-04-16 13:17:24 +02:00
parent 360741674d
commit 3cf1ebc09b
4 changed files with 49 additions and 25 deletions
@@ -304,15 +304,16 @@ class WatchTogetherProvider with ChangeNotifier {
final probe = WatchTogetherPeerService(customBaseUrl: customRelayUrl);
try {
final becameHost = await probe.joinOrCreateSession(sessionId);
final shouldBeHost = becameHost || probe.connectedPeers.isEmpty;
await probe.disconnect();
probe.dispose();
if (becameHost) {
if (shouldBeHost) {
await createSession(controlMode: controlMode, displayName: displayName, sessionId: sessionId);
} else {
await joinSession(sessionId, displayName: displayName);
}
return becameHost;
return shouldBeHost;
} catch (e) {
await probe.disconnect();
probe.dispose();
@@ -460,14 +461,13 @@ class WatchTogetherProvider with ChangeNotifier {
);
}
// If we're the host, send our join info back so the new peer
// adds us to their participant list. This is done at provider
// level (in addition to sync manager) so it works even when
// no player is attached yet.
if (isHost && _peerService != null) {
// Send our join info back so the new peer adds us to their
// participant list. Every peer does this (not just the host)
// so that late joiners learn about all existing participants.
if (_peerService != null) {
_peerService!.sendTo(
message.peerId!,
SyncMessage.join(peerId: _peerService!.myPeerId!, displayName: _displayName, isHost: true),
SyncMessage.join(peerId: _peerService!.myPeerId!, displayName: _displayName, isHost: isHost),
);
}
@@ -221,7 +221,7 @@ class _NotInSessionViewState extends State<_NotInSessionView> {
controlMode: controlMode,
displayName: _plexDisplayName,
);
await RecentRoomsService.addOrUpdateRoom(sessionId);
await RecentRoomsService.addOrUpdateRoom(sessionId, controlMode: controlMode);
if (mounted) setState(() => _recentRooms = RecentRoomsService.getRecentRooms());
} catch (e) {
appLogger.e('Failed to create session', error: e);
@@ -299,7 +299,11 @@ class _NotInSessionViewState extends State<_NotInSessionView> {
setState(() => _enteringRoomCode = room.code);
try {
await widget.watchTogether.enterRoom(room.code, displayName: _plexDisplayName);
await widget.watchTogether.enterRoom(
room.code,
controlMode: room.controlMode ?? ControlMode.anyone,
displayName: _plexDisplayName,
);
await RecentRoomsService.addOrUpdateRoom(room.code);
if (mounted) setState(() => _recentRooms = RecentRoomsService.getRecentRooms());
} catch (e) {
@@ -1,30 +1,39 @@
import 'dart:convert';
import '../../services/settings_service.dart';
import '../models/watch_session.dart';
class RecentRoom {
final String code;
final String? name;
final DateTime lastUsed;
final ControlMode? controlMode;
const RecentRoom({required this.code, this.name, required this.lastUsed});
const RecentRoom({required this.code, this.name, required this.lastUsed, this.controlMode});
Map<String, dynamic> toJson() => {
'code': code,
if (name != null) 'name': name,
'lastUsed': lastUsed.millisecondsSinceEpoch,
if (controlMode != null) 'controlMode': controlMode!.index,
};
factory RecentRoom.fromJson(Map<String, dynamic> json) => RecentRoom(
code: json['code'] as String,
name: json['name'] as String?,
lastUsed: DateTime.fromMillisecondsSinceEpoch(json['lastUsed'] as int),
);
factory RecentRoom.fromJson(Map<String, dynamic> json) {
final modeIndex = json['controlMode'] as int?;
return RecentRoom(
code: json['code'] as String,
name: json['name'] as String?,
lastUsed: DateTime.fromMillisecondsSinceEpoch(json['lastUsed'] as int),
controlMode: modeIndex != null ? ControlMode.values[modeIndex] : null,
);
}
RecentRoom copyWith({String? code, String? name, DateTime? lastUsed, bool clearName = false}) => RecentRoom(
RecentRoom copyWith({String? code, String? name, DateTime? lastUsed, ControlMode? controlMode, bool clearName = false}) =>
RecentRoom(
code: code ?? this.code,
name: clearName ? null : (name ?? this.name),
lastUsed: lastUsed ?? this.lastUsed,
controlMode: controlMode ?? this.controlMode,
);
}
@@ -50,13 +59,17 @@ class RecentRoomsService {
await SettingsService.instanceOrNull?.setRecentRooms(jsonEncode(rooms.map((r) => r.toJson()).toList()));
}
static Future<void> addOrUpdateRoom(String code, {String? name}) async {
static Future<void> addOrUpdateRoom(String code, {String? name, ControlMode? controlMode}) async {
final rooms = getRecentRooms();
final index = rooms.indexWhere((r) => r.code == code);
if (index >= 0) {
rooms[index] = rooms[index].copyWith(lastUsed: DateTime.now(), name: name ?? rooms[index].name);
rooms[index] = rooms[index].copyWith(
lastUsed: DateTime.now(),
name: name ?? rooms[index].name,
controlMode: controlMode,
);
} else {
rooms.add(RecentRoom(code: code, name: name, lastUsed: DateTime.now()));
rooms.add(RecentRoom(code: code, name: name, lastUsed: DateTime.now(), controlMode: controlMode));
}
await _save(rooms);
}