report errors from ErrorBoundary on GroupCall and Member in UI

UI is still very crude fwiw
This commit is contained in:
Bruno Windels 2023-01-09 14:04:13 +01:00
parent 1e4180a71f
commit fef7af3b31
4 changed files with 49 additions and 5 deletions

View File

@ -39,7 +39,11 @@ export class CallViewModel extends ViewModel<Options> {
constructor(options: Options) {
super(options);
const ownMemberViewModelMap = new ObservableValueMap("self", new EventObservableValue(this.call, "change"))
const callObservable = new EventObservableValue(this.call, "change");
this.track(callObservable.subscribe(() => {
this.emitChange();
}));
const ownMemberViewModelMap = new ObservableValueMap("self", callObservable)
.mapValues((call, emitChange) => new OwnMemberViewModel(this.childOptions({call, emitChange})), () => {});
this.memberViewModels = this.call.members
.filterValues(member => member.isConnected)
@ -79,6 +83,10 @@ export class CallViewModel extends ViewModel<Options> {
return this.call.id;
}
get error(): string | undefined {
return this.call.error?.message;
}
private get call(): GroupCall {
return this.getOption("call");
}
@ -135,6 +143,10 @@ class OwnMemberViewModel extends ViewModel<Options> implements IStreamViewModel
}));
}
get error(): string | undefined {
return undefined;
}
get stream(): Stream | undefined {
return this.call.localPreviewMedia?.userMedia;
}
@ -195,6 +207,10 @@ export class CallMemberViewModel extends ViewModel<MemberOptions> implements ISt
return this.member.remoteMedia?.userMedia;
}
get error(): string | undefined {
return this.member.error?.message;
}
private get member(): Member {
return this.getOption("member");
}
@ -242,4 +258,5 @@ export interface IStreamViewModel extends AvatarSource, ViewModel {
get stream(): Stream | undefined;
get isCameraMuted(): boolean;
get isMicrophoneMuted(): boolean;
get error(): string | undefined;
}

View File

@ -74,9 +74,14 @@ export class CallTile extends SimpleTile {
async join() {
if (this.canJoin) {
const stream = await this.platform.mediaDevices.getMediaTracks(false, true);
const localMedia = new LocalMedia().withUserMedia(stream);
await this._call.join(localMedia);
try {
const stream = await this.platform.mediaDevices.getMediaTracks(false, true);
const localMedia = new LocalMedia().withUserMedia(stream);
await this._call.join(localMedia);
} catch (err) {
this._error = err;
this.emitChange("error");
}
}
}

View File

@ -24,6 +24,14 @@ limitations under the License.
grid-row: 1;
}
.CallView_error {
color: red;
font-weight: bold;
align-self: start;
justify-self: center;
margin: 16px;
}
.CallView_members {
display: grid;
gap: 12px;
@ -59,6 +67,14 @@ limitations under the License.
justify-self: center;
}
.StreamView_error {
color: red;
font-weight: bold;
align-self: start;
justify-self: center;
margin: 16px;
}
.StreamView_muteStatus {
align-self: start;
justify-self: end;

View File

@ -43,7 +43,10 @@ export class CallView extends TemplateView<CallViewModel> {
"CallView_unmutedCamera": vm => !vm.isCameraMuted,
}, onClick: disableTargetCallback(() => vm.toggleCamera())}),
t.button({className: "CallView_hangup", onClick: disableTargetCallback(() => vm.hangup())}),
])
]),
t.if(vm => !!vm.error, t => {
return t.div({className: "CallView_error"}, vm => vm.error);
})
]);
}
@ -112,6 +115,9 @@ class StreamView extends TemplateView<IStreamViewModel> {
microphoneMuted: vm => vm.isMicrophoneMuted && !vm.isCameraMuted,
cameraMuted: vm => vm.isCameraMuted,
}
}),
t.if(vm => !!vm.error, t => {
return t.div({className: "StreamView_error"}, vm => vm.error);
})
]);
}