user error view model in room, also when starting call

This commit is contained in:
Bruno Windels 2023-01-10 12:08:10 +01:00
parent b8bc6edbc0
commit f15e849f54
2 changed files with 40 additions and 33 deletions

View File

@ -23,6 +23,7 @@ import {avatarInitials, getIdentifierColorNumber, getAvatarHttpUrl} from "../../
import {ViewModel} from "../../ViewModel"; import {ViewModel} from "../../ViewModel";
import {imageToInfo} from "../common.js"; import {imageToInfo} from "../common.js";
import {LocalMedia} from "../../../matrix/calls/LocalMedia"; import {LocalMedia} from "../../../matrix/calls/LocalMedia";
import { ErrorViewModel } from "../../ErrorViewModel";
// TODO: remove fallback so default isn't included in bundle for SDK users that have their custom tileClassForEntry // TODO: remove fallback so default isn't included in bundle for SDK users that have their custom tileClassForEntry
// this is a breaking SDK change though to make this option mandatory // this is a breaking SDK change though to make this option mandatory
import {tileClassForEntry as defaultTileClassForEntry} from "./timeline/tiles/index"; import {tileClassForEntry as defaultTileClassForEntry} from "./timeline/tiles/index";
@ -36,8 +37,7 @@ export class RoomViewModel extends ViewModel {
this._tileClassForEntry = tileClassForEntry ?? defaultTileClassForEntry; this._tileClassForEntry = tileClassForEntry ?? defaultTileClassForEntry;
this._tileOptions = undefined; this._tileOptions = undefined;
this._onRoomChange = this._onRoomChange.bind(this); this._onRoomChange = this._onRoomChange.bind(this);
this._timelineError = null; this._errorViewModel = null;
this._sendError = null;
this._composerVM = null; this._composerVM = null;
if (room.isArchived) { if (room.isArchived) {
this._composerVM = new ArchivedViewModel(this.childOptions({archivedRoom: room})); this._composerVM = new ArchivedViewModel(this.childOptions({archivedRoom: room}));
@ -73,6 +73,14 @@ export class RoomViewModel extends ViewModel {
} }
} }
_reportError(error) {
this._errorViewModel = new ErrorViewModel(this.childOptions({error, onClose: () => {
this._errorViewModel = null;
this.emitChange("errorViewModel");
}}));
this.emitChange("errorViewModel");
}
async load() { async load() {
this._room.on("change", this._onRoomChange); this._room.on("change", this._onRoomChange);
try { try {
@ -88,10 +96,8 @@ export class RoomViewModel extends ViewModel {
timeline, timeline,
}))); })));
this.emitChange("timelineViewModel"); this.emitChange("timelineViewModel");
} catch (err) { } catch (error) {
console.error(`room.openTimeline(): ${err.message}:\n${err.stack}`); this._reportError(error);
this._timelineError = err;
this.emitChange("error");
} }
this._clearUnreadAfterDelay(); this._clearUnreadAfterDelay();
} }
@ -143,14 +149,8 @@ export class RoomViewModel extends ViewModel {
get timelineViewModel() { return this._timelineVM; } get timelineViewModel() { return this._timelineVM; }
get isEncrypted() { return this._room.isEncrypted; } get isEncrypted() { return this._room.isEncrypted; }
get error() { get errorViewModel() {
if (this._timelineError) { return this._errorViewModel;
return `Something went wrong loading the timeline: ${this._timelineError.message}`;
}
if (this._sendError) {
return `Something went wrong sending your message: ${this._sendError.message}`;
}
return "";
} }
get avatarLetter() { get avatarLetter() {
@ -215,11 +215,8 @@ export class RoomViewModel extends ViewModel {
} else { } else {
await this._room.sendEvent("m.room.message", {msgtype, body: message}); await this._room.sendEvent("m.room.message", {msgtype, body: message});
} }
} catch (err) { } catch (error) {
console.error(`room.sendMessage(): ${err.message}:\n${err.stack}`); this._reportError(error);
this._sendError = err;
this._timelineError = null;
this.emitChange("error");
return false; return false;
} }
return true; return true;
@ -289,10 +286,8 @@ export class RoomViewModel extends ViewModel {
attachments["info.thumbnail_url"] = attachments["info.thumbnail_url"] =
this._room.createAttachment(thumbnail.blob, file.name); this._room.createAttachment(thumbnail.blob, file.name);
await this._room.sendEvent("m.room.message", content, attachments); await this._room.sendEvent("m.room.message", content, attachments);
} catch (err) { } catch (error) {
this._sendError = err; this._reportError(error);
this.emitChange("error");
console.error(err.stack);
} }
} }
@ -331,10 +326,8 @@ export class RoomViewModel extends ViewModel {
this._room.createAttachment(thumbnail.blob, file.name); this._room.createAttachment(thumbnail.blob, file.name);
} }
await this._room.sendEvent("m.room.message", content, attachments); await this._room.sendEvent("m.room.message", content, attachments);
} catch (err) { } catch (error) {
this._sendError = err; this._reportError(error);
this.emitChange("error");
console.error(err.stack);
} }
} }
@ -364,15 +357,28 @@ export class RoomViewModel extends ViewModel {
} }
async startCall() { async startCall() {
let localMedia;
try { try {
const session = this.getOption("session");
const stream = await this.platform.mediaDevices.getMediaTracks(false, true); const stream = await this.platform.mediaDevices.getMediaTracks(false, true);
const localMedia = new LocalMedia().withUserMedia(stream); localMedia = new LocalMedia().withUserMedia(stream);
} catch (err) {
this._reportError(new Error(`Could not get local audio and/or video stream: ${err.message}`));
return;
}
const session = this.getOption("session");
let call;
try {
// this will set the callViewModel above as a call will be added to callHandler.calls // this will set the callViewModel above as a call will be added to callHandler.calls
const call = await session.callHandler.createCall(this._room.id, "m.video", "A call " + Math.round(this.platform.random() * 100)); call = await session.callHandler.createCall(this._room.id, "m.video", "A call " + Math.round(this.platform.random() * 100));
} catch (err) {
this._reportError(new Error(`Could not create call: ${err.message}`));
return;
}
try {
await call.join(localMedia); await call.join(localMedia);
} catch (err) { } catch (err) {
console.error(err.stack); this._reportError(new Error(`Could not join call: ${err.message}`));
return;
} }
} }
} }

View File

@ -15,7 +15,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import {TemplateView} from "../../general/TemplateView"; import {TemplateView} from "../../general/TemplateView";
import {Popup} from "../../general/Popup.js"; import {Popup} from "../../general/Popup.js";
import {Menu} from "../../general/Menu.js"; import {Menu} from "../../general/Menu.js";
import {TimelineView} from "./TimelineView"; import {TimelineView} from "./TimelineView";
@ -24,6 +24,7 @@ import {MessageComposer} from "./MessageComposer.js";
import {RoomArchivedView} from "./RoomArchivedView.js"; import {RoomArchivedView} from "./RoomArchivedView.js";
import {AvatarView} from "../../AvatarView.js"; import {AvatarView} from "../../AvatarView.js";
import {CallView} from "./CallView"; import {CallView} from "./CallView";
import { ErrorView } from "../../general/ErrorView";
export class RoomView extends TemplateView { export class RoomView extends TemplateView {
constructor(vm, viewClassForTile) { constructor(vm, viewClassForTile) {
@ -53,7 +54,7 @@ export class RoomView extends TemplateView {
}) })
]), ]),
t.div({className: "RoomView_body"}, [ t.div({className: "RoomView_body"}, [
t.div({className: "RoomView_error"}, vm => vm.error), t.if(vm => vm.errorViewModel, t => t.div({className: "RoomView_error"}, t.view(new ErrorView(vm.errorViewModel)))),
t.mapView(vm => vm.callViewModel, callViewModel => callViewModel ? new CallView(callViewModel) : null), t.mapView(vm => vm.callViewModel, callViewModel => callViewModel ? new CallView(callViewModel) : null),
t.mapView(vm => vm.timelineViewModel, timelineViewModel => { t.mapView(vm => vm.timelineViewModel, timelineViewModel => {
return timelineViewModel ? return timelineViewModel ?