VERSION_CHECK_INTERVAL_MS, VERSION_CHECK_INTERVAL_MS);
}
final RandomProviderImpl random =
// TODO(ohler): Get a stronger RandomProvider.
RandomProviderImpl.ofSeed(randomSeed);
final RandomBase64Generator random64 = new RandomBase64Generator(new RandomProvider() {
@Override public int nextInt(int upperBound) {
return random.nextInt(upperBound);
}});
final ParticipantId userId;
try {
userId = ParticipantId.of(userIdString);
} catch (InvalidParticipantAddress e1) {
Window.alert("Invalid user id received from server: " + userIdString);
return;
}
convObjectId = new SlobId(convObjectIdString);
idGenerator = new IdHack.MinimalIdGenerator(
IdHack.convWaveletIdFromObjectId(convObjectId),
useUdw ? IdHack.udwWaveletIdFromObjectId(udwObjectId)
// Some code depends on this not to return null, so let's return
// something.
: IdHack.DISABLED_UDW_ID,
random64);
// TODO(ohler): Make the server's response to the contacts RPC indicate
// whether an OAuth token is needed, and enable the button dynamically when
// appropriate, rather than statically.
UIObject.setVisible(Document.get().getElementById("enableAvatarsButton"),
!haveOAuthToken);
@Nullable final LoadWaveService loadWaveService = isLive ? new LoadWaveService(rpc) : null;
@Nullable final ChannelConnectService channelService =
isLive ? new ChannelConnectService(rpc) : null;
new Stages() {
@Override
protected AsyncHolder<StageZero> createStageZeroLoader() {
return new StageZero.DefaultProvider() {
@Override
protected UncaughtExceptionHandler createUncaughtExceptionHandler() {
return WalkaroundUncaughtExceptionHandler.INSTANCE;
}
};
}
@Override
protected AsyncHolder<StageOne> createStageOneLoader(StageZero zero) {
return new StageOne.DefaultProvider(zero) {
protected final ParticipantViewImpl.Helper<ParticipantAvatarDomImpl> participantHelper =
new ParticipantViewImpl.Helper<ParticipantAvatarDomImpl>() {
@Override public void remove(ParticipantAvatarDomImpl impl) {
impl.remove();
}
@Override public ProfilePopupView showParticipation(ParticipantAvatarDomImpl impl) {
return new ProfilePopupWidget(impl.getElement(),
AlignedPopupPositioner.BELOW_RIGHT);
}
};
@Override protected UpgradeableDomAsViewProvider createViewProvider() {
return new FullStructure(createCssProvider()) {
@Override public ParticipantView asParticipant(Element e) {
return e == null ? null : new ParticipantViewImpl<ParticipantAvatarDomImpl>(
participantHelper, ParticipantAvatarDomImpl.of(e));
}
};
}
};
}
@Override
protected AsyncHolder<StageTwo> createStageTwoLoader(final StageOne one) {
return new StageTwo.DefaultProvider(one, null) {
WaveViewData waveData;
StringMap<DocOp> diffMap = CollectionUtils.createStringMap();
@Override protected DomRenderer createRenderer() {
final BlipQueueRenderer pager = getBlipQueue();
DocRefRenderer docRenderer = new DocRefRenderer() {
@Override
public UiBuilder render(
ConversationBlip blip, IdentityMap<ConversationThread, UiBuilder> replies) {
// Documents are rendered blank, and filled in later when
// they get paged in.
pager.add(blip);
return DocRefRenderer.EMPTY.render(blip, replies);
}
};
RenderingRules<UiBuilder> rules = new MyFullDomRenderer(
getBlipDetailer(), docRenderer, getProfileManager(),
getViewIdMapper(), createViewFactories(), getThreadReadStateMonitor()) {
@Override
public UiBuilder render(Conversation conversation, ParticipantId participant) {
// Same as super class, but using avatars instead of names.
Profile profile = getProfileManager().getProfile(participant);
String id = getViewIdMapper().participantOf(conversation, participant);
ParticipantAvatarViewBuilder participantUi =
ParticipantAvatarViewBuilder.create(id);
participantUi.setAvatar(profile.getImageUrl());
participantUi.setName(profile.getFullName());
return participantUi;
}
};
return new HtmlDomRenderer(ReductionBasedRenderer.of(rules, getConversations()));
}
@Override
protected ProfileManager createProfileManager() {
return ContactsManager.create(rpc);
}
@Override
protected void create(final Accessor<StageTwo> whenReady) {
super.create(whenReady);
}
@Override
protected IdGenerator createIdGenerator() {
return idGenerator;
}
@Override
protected void fetchWave(final Accessor<WaveViewData> whenReady) {
wavelets.updateData(
parseConvWaveletData(
convConnectResponse, convSnapshot,
getDocumentRegistry(), diffMap));
if (useUdw) {
wavelets.updateData(
parseUdwData(
udwData.getConnectResponse(),
udwData.getSnapshot(),
getDocumentRegistry()));
}
Document.get().getElementById(WAVEPANEL_PLACEHOLDER).setInnerText("");
waveData = createWaveViewData();
whenReady.use(waveData);
}
@Override
protected WaveDocuments<LazyContentDocument> createDocumentRegistry() {
IndexedDocumentImpl.performValidation = false;
DocumentFactory<?> dataDocFactory =
ObservablePluggableMutableDocument.createFactory(createSchemas());
DocumentFactory<LazyContentDocument> blipDocFactory =
new DocumentFactory<LazyContentDocument>() {
private final Registries registries = RegistriesHolder.get();
@Override
public LazyContentDocument create(
WaveletId waveletId, String docId, DocInitialization content) {
SimpleDiffDoc diff = SimpleDiffDoc.create(content, diffMap.get(docId));
return LazyContentDocument.create(registries, diff);
}
};
return WaveDocuments.create(blipDocFactory, dataDocFactory);
}
@Override
protected ParticipantId createSignedInUser() {
return userId;
}
@Override
protected String createSessionId() {
// TODO(ohler): Write a note here about what this is and how it
// interacts with walkaround's session management.
return random64.next(6);
}
@Override
protected MuxConnector createConnector() {
return new MuxConnector() {