From c2a1b62c8badfd2cfda4332f02d4d3168c8521cc Mon Sep 17 00:00:00 2001 From: Sean Date: Mon, 22 Jun 2020 15:34:42 +0200 Subject: [PATCH] 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 --- .../app/core/core-services/auth.service.ts | 6 +- .../components/jitsi/jitsi.component.html | 51 ++--- .../components/jitsi/jitsi.component.scss | 42 ++-- .../components/jitsi/jitsi.component.ts | 181 ++++++++---------- .../assignment-list.component.html | 2 +- client/src/app/site/site.component.scss | 4 - 6 files changed, 146 insertions(+), 140 deletions(-) diff --git a/client/src/app/core/core-services/auth.service.ts b/client/src/app/core/core-services/auth.service.ts index 4a8691d39..0b2d2004e 100644 --- a/client/src/app/core/core-services/auth.service.ts +++ b/client/src/app/core/core-services/auth.service.ts @@ -8,6 +8,7 @@ import { DEFAULT_AUTH_TYPE, UserAuthType } from 'app/shared/models/users/user'; import { DataStoreService } from './data-store.service'; import { HttpService } from './http.service'; import { OpenSlidesService } from './openslides.service'; +import { StorageService } from './storage.service'; /** * Authenticates an OpenSlides user with username and password @@ -29,7 +30,8 @@ export class AuthService { private operator: OperatorService, private OpenSlides: OpenSlidesService, 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. } this.router.navigate(['/']); + await this.storageService.clear(); await this.DS.clear(); await this.operator.setWhoAmI(response); await this.OpenSlides.reboot(); } else if (authType === 'saml') { + await this.storageService.clear(); await this.DS.clear(); await this.operator.setWhoAmI(null); window.location.href = environment.urlPrefix + '/saml/?slo'; // Bye diff --git a/client/src/app/shared/components/jitsi/jitsi.component.html b/client/src/app/shared/components/jitsi/jitsi.component.html index 7f75d9967..7a8c02e11 100644 --- a/client/src/app/shared/components/jitsi/jitsi.component.html +++ b/client/src/app/shared/components/jitsi/jitsi.component.html @@ -1,29 +1,30 @@ - -
-
- +
+ +
+
+ - -
- + +
+ +
@@ -172,7 +173,7 @@
{{ 'The livestream is already running in your OpenSlides session.' | translate }} diff --git a/client/src/app/shared/components/jitsi/jitsi.component.scss b/client/src/app/shared/components/jitsi/jitsi.component.scss index 58985deed..9ef6e1fa6 100644 --- a/client/src/app/shared/components/jitsi/jitsi.component.scss +++ b/client/src/app/shared/components/jitsi/jitsi.component.scss @@ -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 { display: none; } -.jitsi-iframe-wrapper { - height: 70vh; -} - -.minimize-jitsi-dialog-button { - margin-left: auto !important; - span { - line-height: initial; - } -} - .jitsi-integration { + z-index: 99; + position: fixed; + right: 0; + bottom: 0; + .cast-shadow { box-shadow: -3px -3px 10px 0px rgba(0, 0, 0, 0.2) !important; } diff --git a/client/src/app/shared/components/jitsi/jitsi.component.ts b/client/src/app/shared/components/jitsi/jitsi.component.ts index 12ca35a4f..4ff181755 100644 --- a/client/src/app/shared/components/jitsi/jitsi.component.ts +++ b/client/src/app/shared/components/jitsi/jitsi.component.ts @@ -1,27 +1,17 @@ -import { - Component, - ElementRef, - HostListener, - OnDestroy, - OnInit, - TemplateRef, - ViewChild, - ViewEncapsulation -} from '@angular/core'; -import { MatDialog, MatDialogRef } from '@angular/material/dialog'; +import { Component, ElementRef, HostListener, OnDestroy, OnInit, ViewChild, ViewEncapsulation } from '@angular/core'; +import { MatSnackBar } from '@angular/material/snack-bar'; import { Title } from '@angular/platform-browser'; import { StorageMap } from '@ngx-pwa/local-storage'; import { TranslateService } from '@ngx-translate/core'; import { distinctUntilChanged } from 'rxjs/operators'; -import { BaseComponent } from 'app/base.component'; import { ConstantsService } from 'app/core/core-services/constants.service'; import { OperatorService } from 'app/core/core-services/operator.service'; import { Deferred } from 'app/core/promises/deferred'; import { UserRepositoryService } from 'app/core/repositories/users/user-repository.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; @@ -66,7 +56,7 @@ enum ConferenceState { styleUrls: ['./jitsi.component.scss'], encapsulation: ViewEncapsulation.None }) -export class JitsiComponent extends BaseComponent implements OnInit, OnDestroy { +export class JitsiComponent extends BaseViewComponent implements OnInit, OnDestroy { public enableJitsi: boolean; private autoconnect: boolean; @@ -87,11 +77,6 @@ export class JitsiComponent extends BaseComponent implements OnInit, OnDestroy { @ViewChild('jitsi') private jitsiNode: ElementRef; - @ViewChild('conferenceDialog', { static: true }) - public conferenceDialog: TemplateRef; - - private confDialogRef: MatDialogRef; - // JitsiMeet api object private api: any | null; @@ -109,8 +94,8 @@ export class JitsiComponent extends BaseComponent implements OnInit, OnDestroy { private configsLoaded: Deferred = new Deferred(); // storage locks - public isJitsiActiveInAnotherTab: boolean; - public streamActiveInAnotherTab: boolean; + public isJitsiActiveInAnotherTab = false; + public streamActiveInAnotherTab = false; private RTC_LOGGED_STORAGE_KEY = 'rtcIsLoggedIn'; private STREAM_RUNNING_STORAGE_KEY = 'streamIsRunning'; @@ -176,26 +161,22 @@ export class JitsiComponent extends BaseComponent implements OnInit, OnDestroy { public constructor( titleService: Title, translate: TranslateService, + snackBar: MatSnackBar, private operator: OperatorService, private storageMap: StorageMap, private userRepo: UserRepositoryService, private constantsService: ConstantsService, - private configService: ConfigService, - private dialog: MatDialog + private configService: ConfigService ) { - super(titleService, translate); + super(titleService, translate, snackBar); } public ngOnInit(): void { - this.confDialogRef = this.dialog.open(this.conferenceDialog, { - ...largeDialogSettings, - panelClass: 'jitsi-dialog-hide', - hasBackdrop: false - }); this.setUp(); } public async ngOnDestroy(): Promise { + super.ngOnDestroy(); this.stopConference(); } @@ -214,25 +195,29 @@ export class JitsiComponent extends BaseComponent implements OnInit, OnDestroy { } private async setUp(): Promise { - this.storageMap - .watch(this.RTC_LOGGED_STORAGE_KEY) - .pipe(distinctUntilChanged()) - .subscribe((inUse: boolean) => { - this.isJitsiActiveInAnotherTab = inUse; - this.lockLoaded.resolve(); - if (!inUse && !this.isJitsiActive) { - this.startJitsi(); - } - }); + this.subscriptions.push( + this.storageMap + .watch(this.RTC_LOGGED_STORAGE_KEY) + .pipe(distinctUntilChanged()) + .subscribe((inUse: boolean) => { + console.log('RTC_LOGGED_STORAGE_KEY is in use: ', inUse); - this.storageMap - .watch(this.STREAM_RUNNING_STORAGE_KEY) - .pipe(distinctUntilChanged()) - .subscribe((running: boolean) => { - this.streamActiveInAnotherTab = running; - }); + this.isJitsiActiveInAnotherTab = inUse; + this.lockLoaded.resolve(); + if (!inUse && !this.isJitsiActive) { + this.startJitsi(); + } + }), + this.storageMap + .watch(this.STREAM_RUNNING_STORAGE_KEY) + .pipe(distinctUntilChanged()) + .subscribe((running: boolean) => { + this.streamActiveInAnotherTab = running; + }) + ); await this.lockLoaded; + this.constantsService.get('Settings').subscribe(settings => { if (settings) { this.jitsiDomain = settings.JITSI_DOMAIN; @@ -243,63 +228,64 @@ export class JitsiComponent extends BaseComponent implements OnInit, OnDestroy { }); await this.constantsLoaded; - this.configService - .get('general_system_conference_auto_connect') - .subscribe(autoconnect => (this.autoconnect = autoconnect)); - this.configService.get('general_system_conference_show').subscribe(show => { - this.enableJitsi = show && !!this.jitsiDomain && !!this.roomName; - if (this.enableJitsi && this.autoconnect) { - this.startJitsi(); - } else { - this.stopJitsi(); - } - }); - - this.configService.get('general_system_conference_los_restriction').subscribe(restricted => { - this.restricted = restricted; - }); - - this.configService.get('general_system_stream_url').subscribe(url => { - this.videoStreamUrl = url; - this.configsLoaded.resolve(); - }); + this.subscriptions.push( + this.configService + .get('general_system_conference_auto_connect') + .subscribe(autoconnect => (this.autoconnect = autoconnect)), + this.configService.get('general_system_conference_show').subscribe(show => { + this.enableJitsi = show && !!this.jitsiDomain && !!this.roomName; + if (this.enableJitsi && this.autoconnect) { + this.startJitsi(); + } else { + this.stopJitsi(); + } + }), + this.configService.get('general_system_conference_los_restriction').subscribe(restricted => { + this.restricted = restricted; + }), + this.configService.get('general_system_stream_url').subscribe(url => { + this.videoStreamUrl = url; + this.configsLoaded.resolve(); + }) + ); await this.configsLoaded; - // after configs are loaded - this.storageMap - .watch(this.CONFERENCE_STATE_STORAGE_KEY) - .pipe(distinctUntilChanged()) - .subscribe((confState: ConferenceState) => { - if (confState in ConferenceState) { - if (this.enableJitsi && (!this.videoStreamUrl || !this.canSeeLiveStream)) { - this.currentState = ConferenceState.jitsi; - } else if (!this.enableJitsi && this.videoStreamUrl && this.canSeeLiveStream) { - this.currentState = ConferenceState.stream; + + this.subscriptions.push( + this.storageMap + .watch(this.CONFERENCE_STATE_STORAGE_KEY) + .pipe(distinctUntilChanged()) + .subscribe((confState: ConferenceState) => { + if (confState in ConferenceState) { + if (this.enableJitsi && (!this.videoStreamUrl || !this.canSeeLiveStream)) { + this.currentState = ConferenceState.jitsi; + } else if (!this.enableJitsi && this.videoStreamUrl && this.canSeeLiveStream) { + this.currentState = ConferenceState.stream; + } else { + this.currentState = confState; + } } else { - this.currentState = confState; + this.setDefaultConfState(); } - } else { - this.setDefaultConfState(); - } - // show stream window when the state changes to stream - 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 - this.operator - .isOnCurrentListOfSpeakersObservable() - .pipe(distinctUntilChanged()) - .subscribe(isOnList => { - this.isOnCurrentLos = isOnList; - console.log('this.isOnCurrentLos: ', this.isOnCurrentLos); - - if (!this.isAccessPermitted) { - this.viewStream(); - } - }); + if (!this.isAccessPermitted) { + this.viewStream(); + } + }) + ); } public toggleMute(): void { @@ -463,13 +449,12 @@ export class JitsiComponent extends BaseComponent implements OnInit, OnDestroy { } public hideJitsiDialog(): void { - this.confDialogRef.addPanelClass('jitsi-dialog-hide'); this.isJitsiDialogOpen = false; } public showJitsiDialog(): void { - this.confDialogRef.removePanelClass('jitsi-dialog-hide'); this.isJitsiDialogOpen = true; + this.showJitsiWindow = false; } public async viewStream(): Promise { diff --git a/client/src/app/site/assignments/components/assignment-list/assignment-list.component.html b/client/src/app/site/assignments/components/assignment-list/assignment-list.component.html index 0c759b59c..369a715fe 100644 --- a/client/src/app/site/assignments/components/assignment-list/assignment-list.component.html +++ b/client/src/app/site/assignments/components/assignment-list/assignment-list.component.html @@ -41,7 +41,7 @@ {{ assignment.getListTitle() }}
- + {{ assignment.phaseString | translate }} diff --git a/client/src/app/site/site.component.scss b/client/src/app/site/site.component.scss index 884823065..44d53e2c0 100644 --- a/client/src/app/site/site.component.scss +++ b/client/src/app/site/site.component.scss @@ -136,10 +136,6 @@ mat-sidenav-container { } .toolbars { - z-index: 99; - position: fixed; - right: 0; - bottom: 0; display: flex; * {