Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion lib/providers/collab/lineup_editing_presence_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,26 @@ final openLineUpItemsProvider =
);

class OpenLineUpItemsNotifier extends Notifier<Map<Object, Set<String>>> {
/// The page each dialog opened on: its items are that page's, and stay
/// so if the page on screen changes while it is open.
final Map<Object, String?> _pageOf = {};

@override
Map<Object, Set<String>> build() => const {};

void open(Object owner, Set<String> itemIds) {
_pageOf[owner] = ref.read(strategyPageSessionProvider).activePageId;
state = {...state, owner: itemIds};
}

void close(Object owner) {
_pageOf.remove(owner);
if (!state.containsKey(owner)) return;
state = {...state}..remove(owner);
}

/// The page [owner] opened on.
String? pageOf(Object owner) => _pageOf[owner];
}

/// The lineup groups this user is editing on the page on screen: those of
Expand All @@ -39,14 +48,16 @@ final myLineupEditingProvider = Provider<PresenceEditing?>((ref) {
final held = ref.watch(editorHeldEntitiesProvider) ?? const <String>{};
final placement = ref.watch(lineUpProvider.select((s) => s.placement));
final open = ref.watch(openLineUpItemsProvider);
final openNotifier = ref.read(openLineUpItemsProvider.notifier);
ref.watch(lineupGroupMemoryRevisionProvider);
final liveSync = ref.read(activePageLiveSyncProvider.notifier);
final groupIds = {
for (final id in {
...held,
if (placement?.pinnedOriginId case final id?) id,
if (placement?.pinnedLandingId case final id?) id,
for (final ids in open.values) ...ids,
for (final MapEntry(key: owner, value: ids) in open.entries)
if (openNotifier.pageOf(owner) == pageId) ...ids,
})
if (liveSync.lineupGroupOf(pageId, id) case final group?) group,
};
Expand Down
13 changes: 9 additions & 4 deletions presence/src/room.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,8 +192,13 @@ export class PresenceRoom extends DurableObject<Env> {
this.drop(ws, self, CLOSE_PASS_EXPIRED, "Invalid renewal");
return;
}
// Verifying awaited: the cursor or what is being edited may have
// changed meanwhile, or the socket closed. Renew what it holds now,
// never the state from before the wait.
const current = attachmentOf(ws);
if (current === null) return;
const renewed: Attachment = {
...self,
...current,
lastRenewAt: now,
exp: claims.exp,
name: claims.name,
Expand All @@ -205,9 +210,9 @@ export class PresenceRoom extends DurableObject<Env> {
// Name, avatar, or role may have changed since the last pass; a join
// for a known sid replaces that peer.
if (
renewed.name !== self.name ||
renewed.avatar !== self.avatar ||
renewed.role !== self.role
renewed.name !== current.name ||
renewed.avatar !== current.avatar ||
renewed.role !== current.role
) {
this.broadcast({ t: "join", peer: toPeer(renewed) }, ws);
}
Expand Down
9 changes: 8 additions & 1 deletion test/providers/lineup_editing_presence_provider_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -164,14 +164,21 @@ void main() {
);
});

test('groups are those of the page on screen', () {
test('a dialog edits the groups of the page it opened on, only there', () {
container
.read(openLineUpItemsProvider.notifier)
.open(Object(), {'landing-a', 'landing-b'});
final session = container.read(strategyPageSessionProvider.notifier);
session.setStateForTest(
container.read(strategyPageSessionProvider).copyWith(activePageId: 'p2'),
);
// Page 2 has lineups under the same ids, in other groups; the dialog
// still shows page 1's, so it edits nothing here.
expect(editing(), isNull);

container
.read(openLineUpItemsProvider.notifier)
.open(Object(), {'landing-a'});
expect(
editing(),
const PresenceEditing(pageId: 'p2', groupIds: {'group-a2'}),
Expand Down
Loading