Replace jitsi mat dialog

Replace Jitsis Mat Dialog with an div container
Fixes an issue where observables in jitsi would register multiple times
Clear the IndexedDB on logout
This commit is contained in:
Sean 2020-06-22 15:34:42 +02:00
parent bb10c25974
commit c2a1b62c8b
6 changed files with 146 additions and 140 deletions

View File

@ -8,6 +8,7 @@ import { DEFAULT_AUTH_TYPE, UserAuthType } from 'app/shared/models/users/user';
import { DataStoreService } from './data-store.service'; import { DataStoreService } from './data-store.service';
import { HttpService } from './http.service'; import { HttpService } from './http.service';
import { OpenSlidesService } from './openslides.service'; import { OpenSlidesService } from './openslides.service';
import { StorageService } from './storage.service';
/** /**
* Authenticates an OpenSlides user with username and password * Authenticates an OpenSlides user with username and password
@ -29,7 +30,8 @@ export class AuthService {
private operator: OperatorService, private operator: OperatorService,
private OpenSlides: OpenSlidesService, private OpenSlides: OpenSlidesService,
private router: Router, private router: Router,
private DS: DataStoreService private DS: DataStoreService,
private storageService: StorageService
) {} ) {}
/** /**
@ -106,10 +108,12 @@ export class AuthService {
// We do nothing on failures. Reboot OpenSlides anyway. // We do nothing on failures. Reboot OpenSlides anyway.
} }
this.router.navigate(['/']); this.router.navigate(['/']);
await this.storageService.clear();
await this.DS.clear(); await this.DS.clear();
await this.operator.setWhoAmI(response); await this.operator.setWhoAmI(response);
await this.OpenSlides.reboot(); await this.OpenSlides.reboot();
} else if (authType === 'saml') { } else if (authType === 'saml') {
await this.storageService.clear();
await this.DS.clear(); await this.DS.clear();
await this.operator.setWhoAmI(null); await this.operator.setWhoAmI(null);
window.location.href = environment.urlPrefix + '/saml/?slo'; // Bye window.location.href = environment.urlPrefix + '/saml/?slo'; // Bye

View File

@ -1,29 +1,30 @@
<!-- iFrame Dialog --> <!-- iFrame Dialog -->
<ng-template #conferenceDialog> <div class="jitsi-fake-dialog-wrapper" [ngClass]="{'jitsi-dialog-hide': !isJitsiDialogOpen}">
<div class="jitsi-iframe-wrapper" #jitsi></div> <mat-card class="jitsi-fake-dialog">
<div mat-dialog-actions> <div class="jitsi-iframe-wrapper" #jitsi></div>
<button <div class="jitsi-dialog-actions">
type="button" <button
mat-button type="button"
color="" mat-button
(click)="openExternal()" color="primary"
matTooltip="{{ 'Open Jitsi in new tab' | translate }}" (click)="openExternal()"
> matTooltip="{{ 'Open Jitsi in new tab' | translate }}"
<mat-icon>open_in_new</mat-icon> >
</button> <mat-icon>open_in_new</mat-icon>
</button>
<button <button
class="minimize-jitsi-dialog-button" type="button"
type="button" mat-button
mat-button color="primary"
color="primary" (click)="hideJitsiDialog()"
(click)="hideJitsiDialog()" >
> <span>{{ 'Minimize' | translate }}</span>
<span>{{ 'Minimize' | translate }}</span> <mat-icon>fullscreen_exit</mat-icon>
<mat-icon>fullscreen_exit</mat-icon> </button>
</button> </div>
</div> </mat-card>
</ng-template> </div>
<div class="jitsi-integration" *ngIf="enableJitsi || (videoStreamUrl && canSeeLiveStream)"> <div class="jitsi-integration" *ngIf="enableJitsi || (videoStreamUrl && canSeeLiveStream)">
<!-- Audio-Conference-bar --> <!-- Audio-Conference-bar -->
@ -172,7 +173,7 @@
<os-vjs-player <os-vjs-player
[videoUrl]="videoStreamUrl" [videoUrl]="videoStreamUrl"
(started)="onSteamStarted()" (started)="onSteamStarted()"
*ngIf="canSeeLiveStream && !streamActiveInAnotherTab || streamRunning" *ngIf="(canSeeLiveStream && !streamActiveInAnotherTab) || streamRunning"
></os-vjs-player> ></os-vjs-player>
<div class="disconnected" *ngIf="streamActiveInAnotherTab && !streamRunning"> <div class="disconnected" *ngIf="streamActiveInAnotherTab && !streamRunning">
<span>{{ 'The livestream is already running in your OpenSlides session.' | translate }}</span> <span>{{ 'The livestream is already running in your OpenSlides session.' | translate }}</span>

View File

@ -1,19 +1,39 @@
.jitsi-fake-dialog-wrapper {
z-index: 98;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
padding: 20px 10% 20px 5%;
.jitsi-fake-dialog {
display: flex;
flex-direction: column;
width: 100%;
height: 90%;
.jitsi-iframe-wrapper {
flex: 1;
}
.jitsi-dialog-actions {
display: flex;
justify-content: space-between;
}
}
}
.jitsi-dialog-hide { .jitsi-dialog-hide {
display: none; display: none;
} }
.jitsi-iframe-wrapper {
height: 70vh;
}
.minimize-jitsi-dialog-button {
margin-left: auto !important;
span {
line-height: initial;
}
}
.jitsi-integration { .jitsi-integration {
z-index: 99;
position: fixed;
right: 0;
bottom: 0;
.cast-shadow { .cast-shadow {
box-shadow: -3px -3px 10px 0px rgba(0, 0, 0, 0.2) !important; box-shadow: -3px -3px 10px 0px rgba(0, 0, 0, 0.2) !important;
} }

View File

@ -1,27 +1,17 @@
import { import { Component, ElementRef, HostListener, OnDestroy, OnInit, ViewChild, ViewEncapsulation } from '@angular/core';
Component, import { MatSnackBar } from '@angular/material/snack-bar';
ElementRef,
HostListener,
OnDestroy,
OnInit,
TemplateRef,
ViewChild,
ViewEncapsulation
} from '@angular/core';
import { MatDialog, MatDialogRef } from '@angular/material/dialog';
import { Title } from '@angular/platform-browser'; import { Title } from '@angular/platform-browser';
import { StorageMap } from '@ngx-pwa/local-storage'; import { StorageMap } from '@ngx-pwa/local-storage';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { distinctUntilChanged } from 'rxjs/operators'; import { distinctUntilChanged } from 'rxjs/operators';
import { BaseComponent } from 'app/base.component';
import { ConstantsService } from 'app/core/core-services/constants.service'; import { ConstantsService } from 'app/core/core-services/constants.service';
import { OperatorService } from 'app/core/core-services/operator.service'; import { OperatorService } from 'app/core/core-services/operator.service';
import { Deferred } from 'app/core/promises/deferred'; import { Deferred } from 'app/core/promises/deferred';
import { UserRepositoryService } from 'app/core/repositories/users/user-repository.service'; import { UserRepositoryService } from 'app/core/repositories/users/user-repository.service';
import { ConfigService } from 'app/core/ui-services/config.service'; import { ConfigService } from 'app/core/ui-services/config.service';
import { largeDialogSettings } from 'app/shared/utils/dialog-settings'; import { BaseViewComponent } from 'app/site/base/base-view';
declare var JitsiMeetExternalAPI: any; declare var JitsiMeetExternalAPI: any;
@ -66,7 +56,7 @@ enum ConferenceState {
styleUrls: ['./jitsi.component.scss'], styleUrls: ['./jitsi.component.scss'],
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class JitsiComponent extends BaseComponent implements OnInit, OnDestroy { export class JitsiComponent extends BaseViewComponent implements OnInit, OnDestroy {
public enableJitsi: boolean; public enableJitsi: boolean;
private autoconnect: boolean; private autoconnect: boolean;
@ -87,11 +77,6 @@ export class JitsiComponent extends BaseComponent implements OnInit, OnDestroy {
@ViewChild('jitsi') @ViewChild('jitsi')
private jitsiNode: ElementRef; private jitsiNode: ElementRef;
@ViewChild('conferenceDialog', { static: true })
public conferenceDialog: TemplateRef<string>;
private confDialogRef: MatDialogRef<any>;
// JitsiMeet api object // JitsiMeet api object
private api: any | null; private api: any | null;
@ -109,8 +94,8 @@ export class JitsiComponent extends BaseComponent implements OnInit, OnDestroy {
private configsLoaded: Deferred<void> = new Deferred(); private configsLoaded: Deferred<void> = new Deferred();
// storage locks // storage locks
public isJitsiActiveInAnotherTab: boolean; public isJitsiActiveInAnotherTab = false;
public streamActiveInAnotherTab: boolean; public streamActiveInAnotherTab = false;
private RTC_LOGGED_STORAGE_KEY = 'rtcIsLoggedIn'; private RTC_LOGGED_STORAGE_KEY = 'rtcIsLoggedIn';
private STREAM_RUNNING_STORAGE_KEY = 'streamIsRunning'; private STREAM_RUNNING_STORAGE_KEY = 'streamIsRunning';
@ -176,26 +161,22 @@ export class JitsiComponent extends BaseComponent implements OnInit, OnDestroy {
public constructor( public constructor(
titleService: Title, titleService: Title,
translate: TranslateService, translate: TranslateService,
snackBar: MatSnackBar,
private operator: OperatorService, private operator: OperatorService,
private storageMap: StorageMap, private storageMap: StorageMap,
private userRepo: UserRepositoryService, private userRepo: UserRepositoryService,
private constantsService: ConstantsService, private constantsService: ConstantsService,
private configService: ConfigService, private configService: ConfigService
private dialog: MatDialog
) { ) {
super(titleService, translate); super(titleService, translate, snackBar);
} }
public ngOnInit(): void { public ngOnInit(): void {
this.confDialogRef = this.dialog.open(this.conferenceDialog, {
...largeDialogSettings,
panelClass: 'jitsi-dialog-hide',
hasBackdrop: false
});
this.setUp(); this.setUp();
} }
public async ngOnDestroy(): Promise<void> { public async ngOnDestroy(): Promise<void> {
super.ngOnDestroy();
this.stopConference(); this.stopConference();
} }
@ -214,25 +195,29 @@ export class JitsiComponent extends BaseComponent implements OnInit, OnDestroy {
} }
private async setUp(): Promise<void> { private async setUp(): Promise<void> {
this.storageMap this.subscriptions.push(
.watch(this.RTC_LOGGED_STORAGE_KEY) this.storageMap
.pipe(distinctUntilChanged()) .watch(this.RTC_LOGGED_STORAGE_KEY)
.subscribe((inUse: boolean) => { .pipe(distinctUntilChanged())
this.isJitsiActiveInAnotherTab = inUse; .subscribe((inUse: boolean) => {
this.lockLoaded.resolve(); console.log('RTC_LOGGED_STORAGE_KEY is in use: ', inUse);
if (!inUse && !this.isJitsiActive) {
this.startJitsi();
}
});
this.storageMap this.isJitsiActiveInAnotherTab = inUse;
.watch(this.STREAM_RUNNING_STORAGE_KEY) this.lockLoaded.resolve();
.pipe(distinctUntilChanged()) if (!inUse && !this.isJitsiActive) {
.subscribe((running: boolean) => { this.startJitsi();
this.streamActiveInAnotherTab = running; }
}); }),
this.storageMap
.watch(this.STREAM_RUNNING_STORAGE_KEY)
.pipe(distinctUntilChanged())
.subscribe((running: boolean) => {
this.streamActiveInAnotherTab = running;
})
);
await this.lockLoaded; await this.lockLoaded;
this.constantsService.get<JitsiSettings>('Settings').subscribe(settings => { this.constantsService.get<JitsiSettings>('Settings').subscribe(settings => {
if (settings) { if (settings) {
this.jitsiDomain = settings.JITSI_DOMAIN; this.jitsiDomain = settings.JITSI_DOMAIN;
@ -243,63 +228,64 @@ export class JitsiComponent extends BaseComponent implements OnInit, OnDestroy {
}); });
await this.constantsLoaded; await this.constantsLoaded;
this.configService
.get<boolean>('general_system_conference_auto_connect')
.subscribe(autoconnect => (this.autoconnect = autoconnect));
this.configService.get<boolean>('general_system_conference_show').subscribe(show => { this.subscriptions.push(
this.enableJitsi = show && !!this.jitsiDomain && !!this.roomName; this.configService
if (this.enableJitsi && this.autoconnect) { .get<boolean>('general_system_conference_auto_connect')
this.startJitsi(); .subscribe(autoconnect => (this.autoconnect = autoconnect)),
} else { this.configService.get<boolean>('general_system_conference_show').subscribe(show => {
this.stopJitsi(); this.enableJitsi = show && !!this.jitsiDomain && !!this.roomName;
} if (this.enableJitsi && this.autoconnect) {
}); this.startJitsi();
} else {
this.configService.get<boolean>('general_system_conference_los_restriction').subscribe(restricted => { this.stopJitsi();
this.restricted = restricted; }
}); }),
this.configService.get<boolean>('general_system_conference_los_restriction').subscribe(restricted => {
this.configService.get<string>('general_system_stream_url').subscribe(url => { this.restricted = restricted;
this.videoStreamUrl = url; }),
this.configsLoaded.resolve(); this.configService.get<string>('general_system_stream_url').subscribe(url => {
}); this.videoStreamUrl = url;
this.configsLoaded.resolve();
})
);
await this.configsLoaded; await this.configsLoaded;
// after configs are loaded
this.storageMap this.subscriptions.push(
.watch(this.CONFERENCE_STATE_STORAGE_KEY) this.storageMap
.pipe(distinctUntilChanged()) .watch(this.CONFERENCE_STATE_STORAGE_KEY)
.subscribe((confState: ConferenceState) => { .pipe(distinctUntilChanged())
if (confState in ConferenceState) { .subscribe((confState: ConferenceState) => {
if (this.enableJitsi && (!this.videoStreamUrl || !this.canSeeLiveStream)) { if (confState in ConferenceState) {
this.currentState = ConferenceState.jitsi; if (this.enableJitsi && (!this.videoStreamUrl || !this.canSeeLiveStream)) {
} else if (!this.enableJitsi && this.videoStreamUrl && this.canSeeLiveStream) { this.currentState = ConferenceState.jitsi;
this.currentState = ConferenceState.stream; } else if (!this.enableJitsi && this.videoStreamUrl && this.canSeeLiveStream) {
this.currentState = ConferenceState.stream;
} else {
this.currentState = confState;
}
} else { } else {
this.currentState = confState; this.setDefaultConfState();
} }
} else { // show stream window when the state changes to stream
this.setDefaultConfState(); if (this.currentState === ConferenceState.stream && !this.streamActiveInAnotherTab) {
} this.showJitsiWindow = true;
// show stream window when the state changes to stream }
if (this.currentState === ConferenceState.stream && !this.streamActiveInAnotherTab) { }),
this.showJitsiWindow = true; // check if the user is on the clos, remove from room if not permitted
} this.operator
}); .isOnCurrentListOfSpeakersObservable()
.pipe(distinctUntilChanged())
.subscribe(isOnList => {
this.isOnCurrentLos = isOnList;
console.log('this.isOnCurrentLos: ', this.isOnCurrentLos);
// check if the user is on the clos, remove from room if not permitted if (!this.isAccessPermitted) {
this.operator this.viewStream();
.isOnCurrentListOfSpeakersObservable() }
.pipe(distinctUntilChanged()) })
.subscribe(isOnList => { );
this.isOnCurrentLos = isOnList;
console.log('this.isOnCurrentLos: ', this.isOnCurrentLos);
if (!this.isAccessPermitted) {
this.viewStream();
}
});
} }
public toggleMute(): void { public toggleMute(): void {
@ -463,13 +449,12 @@ export class JitsiComponent extends BaseComponent implements OnInit, OnDestroy {
} }
public hideJitsiDialog(): void { public hideJitsiDialog(): void {
this.confDialogRef.addPanelClass('jitsi-dialog-hide');
this.isJitsiDialogOpen = false; this.isJitsiDialogOpen = false;
} }
public showJitsiDialog(): void { public showJitsiDialog(): void {
this.confDialogRef.removePanelClass('jitsi-dialog-hide');
this.isJitsiDialogOpen = true; this.isJitsiDialogOpen = true;
this.showJitsiWindow = false;
} }
public async viewStream(): Promise<void> { public async viewStream(): Promise<void> {

View File

@ -41,7 +41,7 @@
{{ assignment.getListTitle() }} {{ assignment.getListTitle() }}
</div> </div>
<mat-chip-list class="ellipsis-overflow" *ngIf="vp.isMobile"> <mat-chip-list class="ellipsis-overflow" *ngIf="vp.isMobile">
<mat-chip color="" selected> <mat-chip color="primary" selected>
{{ assignment.phaseString | translate }} {{ assignment.phaseString | translate }}
</mat-chip> </mat-chip>
</mat-chip-list> </mat-chip-list>

View File

@ -136,10 +136,6 @@ mat-sidenav-container {
} }
.toolbars { .toolbars {
z-index: 99;
position: fixed;
right: 0;
bottom: 0;
display: flex; display: flex;
* { * {