Collaboration
You will learn how several controllers share one live document: each has its own selection and undo history, every change is attributed, and editors show the other participants' carets.
dart
import 'package:vyuh_document/elements.dart';
import 'package:vyuh_document/vyuh_document.dart';
/// A person and an agent editing one live document.
Future<void> main() async {
final configuration = DocumentConfiguration.richText;
final mine = DocumentController(
configuration,
document: Document.of(configuration, [Paragraph('Draft')]).valueOrNull,
author: const Author.person('asha'),
);
final agent = mine.join(author: const Author.agent('reviewer'));
// Every applied change from every participant, attributed.
final subscription = mine.changes.listen((change) {
print('${change.author} ran ${change.command.name} -> r${change.revision}');
});
final paragraph = agent.document.body.first<Paragraph>();
agent.run(InsertText(Position(paragraph, offset: 5), ' (reviewed)'));
// `mine` sees the agent's text at once, but undoes only its own changes.
print(mine.document.plainText); // Draft (reviewed)
print(mine.state.canUndo); // false
await subscription.cancel();
agent.close();
mine.close();
}Participants
| API | Meaning |
|---|---|
Author.person(name), Author.agent(name) | Who a change is attributed to (author.id is person:asha or agent:reviewer) |
DocumentController(config, author:) | The first participant |
controller.join(author:) | Another participant on the same live document |
controller.participantId | Unique per controller, even when two share an author |
controller.changes | Stream<Change> of every applied change from every participant |
controller.close() | Leaves the document; further commands fail with Unsupported |
A Change carries author, participantId, revision, the command and the document after it.
Undo is per participant
Each controller undoes only its own changes, mapped over everyone else's. If both edited the same text, undo fails with Conflict instead of reverting the other person's work.
In the editor
Two DocumentEditors on joined controllers show each other's edits live and draw each other's caret with a name tag. Typing is attributed to the editor's controller.
dart
final mine = DocumentController(notesConfiguration);
final theirs = mine.join(author: const Author.person('sam'));
Row(children: [
Expanded(child: DocumentEditor(controller: mine)),
Expanded(child: DocumentEditor(controller: theirs)),
]);Across processes
To carry changes between processes, build on the engine's collaboration envelopes and DocumentCollaborationTransport (engine.dart).
Next
Agents: give an AI agent its own controller.