Hide conference bar without interaction
Hide the conference bar if there is no stream and no entering permission. Hides the "see stream" button if use user has no permission to see the stream (call list window) Use rxjs combineLatest for easier "dead state" detection with less change pushing
This commit is contained in:
parent
7dcdbb4ee1
commit
8b22f5ff0e
@ -72,15 +72,17 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="exit">
|
<div class="exit">
|
||||||
<!-- Exit jitsi, view stream -->
|
<!-- Exit jitsi, view stream -->
|
||||||
<button
|
<ng-container *osPerms="permission.coreCanSeeLiveStream">
|
||||||
mat-icon-button
|
<button
|
||||||
color="primary"
|
mat-icon-button
|
||||||
matTooltip="{{ 'Continue livestream' | translate }}"
|
color="primary"
|
||||||
(click)="viewStream()"
|
matTooltip="{{ 'Continue livestream' | translate }}"
|
||||||
*ngIf="!!(liveStreamUrl | async)?.trim()"
|
(click)="viewStream()"
|
||||||
>
|
*ngIf="hasLiveStreamUrl | async"
|
||||||
<mat-icon>live_tv</mat-icon>
|
>
|
||||||
</button>
|
<mat-icon>live_tv</mat-icon>
|
||||||
|
</button>
|
||||||
|
</ng-container>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -38,6 +38,8 @@ export class CallComponent extends BaseViewComponentDirective implements OnInit,
|
|||||||
public isJitsiActiveInAnotherTab: Observable<boolean> = this.rtcService.inOtherTab;
|
public isJitsiActiveInAnotherTab: Observable<boolean> = this.rtcService.inOtherTab;
|
||||||
public canEnterCall: Observable<boolean> = this.callRestrictionService.canEnterCallObservable;
|
public canEnterCall: Observable<boolean> = this.callRestrictionService.canEnterCallObservable;
|
||||||
public isJitsiDialogOpen: Observable<boolean> = this.rtcService.showCallDialogObservable;
|
public isJitsiDialogOpen: Observable<boolean> = this.rtcService.showCallDialogObservable;
|
||||||
|
public showParticles: Observable<boolean> = this.applauseService.showParticles;
|
||||||
|
public hasLiveStreamUrl: Observable<boolean> = this.streamService.hasLiveStreamUrlObvervable;
|
||||||
|
|
||||||
public isJitsiActive: boolean;
|
public isJitsiActive: boolean;
|
||||||
public isJoined: boolean;
|
public isJoined: boolean;
|
||||||
@ -64,18 +66,6 @@ export class CallComponent extends BaseViewComponentDirective implements OnInit,
|
|||||||
return this.isJitsiActive && this.isJoined;
|
return this.isJitsiActive && this.isJoined;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get showParticles(): Observable<boolean> {
|
|
||||||
return this.applauseService.showParticles;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get canSeeLiveStream(): Observable<boolean> {
|
|
||||||
return this.streamService.canSeeLiveStreamObservable;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get liveStreamUrl(): Observable<string> {
|
|
||||||
return this.streamService.liveStreamUrlObservable;
|
|
||||||
}
|
|
||||||
|
|
||||||
private autoConnect: boolean;
|
private autoConnect: boolean;
|
||||||
|
|
||||||
@Output()
|
@Output()
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component } from '@angular/core';
|
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core';
|
||||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||||
import { Title } from '@angular/platform-browser';
|
import { Title } from '@angular/platform-browser';
|
||||||
|
|
||||||
@ -18,7 +18,7 @@ import { StreamService } from '../../services/stream.service';
|
|||||||
styleUrls: ['./interaction-container.component.scss'],
|
styleUrls: ['./interaction-container.component.scss'],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
})
|
})
|
||||||
export class InteractionContainerComponent extends BaseViewComponentDirective {
|
export class InteractionContainerComponent extends BaseViewComponentDirective implements OnInit {
|
||||||
public showBody = false;
|
public showBody = false;
|
||||||
|
|
||||||
private streamRunning = false;
|
private streamRunning = false;
|
||||||
@ -63,11 +63,6 @@ export class InteractionContainerComponent extends BaseViewComponentDirective {
|
|||||||
) {
|
) {
|
||||||
super(titleService, translate, matSnackBar);
|
super(titleService, translate, matSnackBar);
|
||||||
this.subscriptions.push(
|
this.subscriptions.push(
|
||||||
interactionService.conferenceStateObservable.pipe(distinctUntilChanged()).subscribe(state => {
|
|
||||||
if (state) {
|
|
||||||
this.clearTitles();
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
rtcService.showCallDialogObservable.subscribe(show => {
|
rtcService.showCallDialogObservable.subscribe(show => {
|
||||||
if (show) {
|
if (show) {
|
||||||
this.showBody = false;
|
this.showBody = false;
|
||||||
@ -91,9 +86,20 @@ export class InteractionContainerComponent extends BaseViewComponentDirective {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ngOnInit(): void {
|
||||||
|
this.subscriptions.push(
|
||||||
|
this.interactionService.conferenceStateObservable.pipe(distinctUntilChanged()).subscribe(state => {
|
||||||
|
if (state) {
|
||||||
|
this.clearTitles();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private clearTitles(): void {
|
private clearTitles(): void {
|
||||||
this.containerHeadTitle = '';
|
this.containerHeadTitle = '';
|
||||||
this.containerHeadSubtitle = '';
|
this.containerHeadSubtitle = '';
|
||||||
|
this.cd.markForCheck();
|
||||||
this.cd.detectChanges();
|
this.cd.detectChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,14 +110,14 @@ export class InteractionContainerComponent extends BaseViewComponentDirective {
|
|||||||
public updateTitle(title: string): void {
|
public updateTitle(title: string): void {
|
||||||
if (title !== this.containerHeadTitle) {
|
if (title !== this.containerHeadTitle) {
|
||||||
this.containerHeadTitle = title ?? '';
|
this.containerHeadTitle = title ?? '';
|
||||||
this.cd.detectChanges();
|
this.cd.markForCheck();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public updateSubtitle(title: string): void {
|
public updateSubtitle(title: string): void {
|
||||||
if (title !== this.containerHeadSubtitle) {
|
if (title !== this.containerHeadSubtitle) {
|
||||||
this.containerHeadSubtitle = title ?? '';
|
this.containerHeadSubtitle = title ?? '';
|
||||||
this.cd.detectChanges();
|
this.cd.markForCheck();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -88,7 +88,7 @@ export class CallRestrictionService {
|
|||||||
) {
|
) {
|
||||||
this.hasToEnterCallSubject.next();
|
this.hasToEnterCallSubject.next();
|
||||||
}
|
}
|
||||||
} else if (operatorClosIndex === UserListIndexType.NotOnList && this.restricted) {
|
} else if (operatorClosIndex === UserListIndexType.NotOnList && this.restricted && !this.canManageSpeaker) {
|
||||||
this.hasToLeaveCallSubject.next();
|
this.hasToLeaveCallSubject.next();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
|
|
||||||
import { BehaviorSubject, Observable } from 'rxjs';
|
import { BehaviorSubject, combineLatest, Observable } from 'rxjs';
|
||||||
import { map } from 'rxjs/operators';
|
import { distinctUntilChanged, map } from 'rxjs/operators';
|
||||||
|
|
||||||
import { ConfigService } from 'app/core/ui-services/config.service';
|
import { ConfigService } from 'app/core/ui-services/config.service';
|
||||||
import { CallRestrictionService } from './call-restriction.service';
|
import { CallRestrictionService } from './call-restriction.service';
|
||||||
@ -9,9 +9,9 @@ import { RtcService } from './rtc.service';
|
|||||||
import { StreamService } from './stream.service';
|
import { StreamService } from './stream.service';
|
||||||
|
|
||||||
export enum ConferenceState {
|
export enum ConferenceState {
|
||||||
none,
|
none = 1,
|
||||||
stream,
|
stream = 2,
|
||||||
jitsi
|
jitsi = 3
|
||||||
}
|
}
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
@ -20,17 +20,14 @@ export enum ConferenceState {
|
|||||||
export class InteractionService {
|
export class InteractionService {
|
||||||
private conferenceStateSubject = new BehaviorSubject<ConferenceState>(ConferenceState.none);
|
private conferenceStateSubject = new BehaviorSubject<ConferenceState>(ConferenceState.none);
|
||||||
public conferenceStateObservable = this.conferenceStateSubject.asObservable();
|
public conferenceStateObservable = this.conferenceStateSubject.asObservable();
|
||||||
public showLiveConfObservable: Observable<boolean>;
|
public showLiveConfObservable: Observable<boolean> = this.configService.get<boolean>(
|
||||||
|
'general_system_conference_show'
|
||||||
|
);
|
||||||
private get conferenceState(): ConferenceState {
|
private get conferenceState(): ConferenceState {
|
||||||
return this.conferenceStateSubject.value;
|
return this.conferenceStateSubject.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private isJitsiEnabled: boolean;
|
|
||||||
private isInCall: boolean;
|
private isInCall: boolean;
|
||||||
private isJitsiActive: boolean;
|
|
||||||
private hasLiveStreamUrl: boolean;
|
|
||||||
private canSeeLiveStream: boolean;
|
|
||||||
private showLiveConf: boolean;
|
|
||||||
|
|
||||||
public get isConfStateStream(): Observable<boolean> {
|
public get isConfStateStream(): Observable<boolean> {
|
||||||
return this.conferenceStateObservable.pipe(map(state => state === ConferenceState.stream));
|
return this.conferenceStateObservable.pipe(map(state => state === ConferenceState.stream));
|
||||||
@ -50,36 +47,38 @@ export class InteractionService {
|
|||||||
private rtcService: RtcService,
|
private rtcService: RtcService,
|
||||||
private callRestrictionService: CallRestrictionService
|
private callRestrictionService: CallRestrictionService
|
||||||
) {
|
) {
|
||||||
this.showLiveConfObservable = this.configService.get<boolean>('general_system_conference_show');
|
combineLatest(
|
||||||
|
this.showLiveConfObservable,
|
||||||
|
this.streamService.hasLiveStreamUrlObvervable,
|
||||||
|
this.streamService.canSeeLiveStreamObservable,
|
||||||
|
this.rtcService.isJitsiEnabledObservable,
|
||||||
|
this.rtcService.isJoinedObservable,
|
||||||
|
this.rtcService.isJitsiActiveObservable,
|
||||||
|
this.callRestrictionService.canEnterCallObservable,
|
||||||
|
(showConf, hasStreamUrl, canSeeStream, jitsiEnabled, inCall, jitsiActive, canEnterCall) => {
|
||||||
|
this.isInCall = inCall;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If you want to somehow simplify this using rxjs merge-map magic or something
|
* most importantly, if there is a call, to not change the state here
|
||||||
* be my guest.
|
*/
|
||||||
*/
|
if (inCall || jitsiActive) {
|
||||||
this.streamService.liveStreamUrlObservable.subscribe(url => {
|
return;
|
||||||
this.hasLiveStreamUrl = !!url?.trim() ?? false;
|
}
|
||||||
this.detectDeadState();
|
if (hasStreamUrl && canSeeStream) {
|
||||||
});
|
return ConferenceState.stream;
|
||||||
|
} else if (showConf && jitsiEnabled && canEnterCall && (!hasStreamUrl || !canSeeStream)) {
|
||||||
this.streamService.canSeeLiveStreamObservable.subscribe(canSee => {
|
return ConferenceState.jitsi;
|
||||||
this.canSeeLiveStream = canSee;
|
} else {
|
||||||
this.detectDeadState();
|
return ConferenceState.none;
|
||||||
});
|
}
|
||||||
|
}
|
||||||
this.rtcService.isJitsiEnabledObservable.subscribe(enabled => {
|
)
|
||||||
this.isJitsiEnabled = enabled;
|
.pipe(distinctUntilChanged())
|
||||||
this.detectDeadState();
|
.subscribe(state => {
|
||||||
});
|
if (state) {
|
||||||
|
this.setConferenceState(state);
|
||||||
this.rtcService.isJoinedObservable.subscribe(joined => {
|
}
|
||||||
this.isInCall = joined;
|
});
|
||||||
this.detectDeadState();
|
|
||||||
});
|
|
||||||
|
|
||||||
this.rtcService.isJitsiActiveObservable.subscribe(isActive => {
|
|
||||||
this.isJitsiActive = isActive;
|
|
||||||
this.detectDeadState();
|
|
||||||
});
|
|
||||||
|
|
||||||
this.callRestrictionService.hasToEnterCallObservable.subscribe(() => {
|
this.callRestrictionService.hasToEnterCallObservable.subscribe(() => {
|
||||||
if (!this.isInCall) {
|
if (!this.isInCall) {
|
||||||
@ -91,13 +90,6 @@ export class InteractionService {
|
|||||||
this.callRestrictionService.hasToLeaveCallObservable.subscribe(() => {
|
this.callRestrictionService.hasToLeaveCallObservable.subscribe(() => {
|
||||||
this.viewStream();
|
this.viewStream();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.showLiveConfObservable.subscribe(showConf => {
|
|
||||||
this.showLiveConf = showConf;
|
|
||||||
this.detectDeadState();
|
|
||||||
});
|
|
||||||
|
|
||||||
this.detectDeadState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async enterCall(): Promise<void> {
|
public async enterCall(): Promise<void> {
|
||||||
@ -117,37 +109,4 @@ export class InteractionService {
|
|||||||
this.conferenceStateSubject.next(newState);
|
this.conferenceStateSubject.next(newState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* this is the "dead" state; you would see the jitsi state; but are not connected
|
|
||||||
* or the connection is prohibited. If this occurs and a live stream
|
|
||||||
* becomes available, switch to the stream state
|
|
||||||
*/
|
|
||||||
private detectDeadState(): void {
|
|
||||||
if (
|
|
||||||
this.isInCall === undefined ||
|
|
||||||
this.isJitsiActive === undefined ||
|
|
||||||
this.hasLiveStreamUrl === undefined ||
|
|
||||||
this.conferenceState === undefined ||
|
|
||||||
this.canSeeLiveStream === undefined ||
|
|
||||||
this.isJitsiEnabled === undefined
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* most importantly, if there is a call, to not change the state!
|
|
||||||
*/
|
|
||||||
if (this.isInCall || this.isJitsiActive) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.hasLiveStreamUrl && this.canSeeLiveStream) {
|
|
||||||
this.viewStream();
|
|
||||||
} else if (this.showLiveConf && (!this.hasLiveStreamUrl || !this.canSeeLiveStream) && this.isJitsiEnabled) {
|
|
||||||
this.enterCall();
|
|
||||||
} else {
|
|
||||||
this.setConferenceState(ConferenceState.none);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ import { Injectable } from '@angular/core';
|
|||||||
|
|
||||||
import { StorageMap } from '@ngx-pwa/local-storage';
|
import { StorageMap } from '@ngx-pwa/local-storage';
|
||||||
import { Observable, Subject } from 'rxjs';
|
import { Observable, Subject } from 'rxjs';
|
||||||
import { distinctUntilChanged } from 'rxjs/operators';
|
import { distinctUntilChanged, map } from 'rxjs/operators';
|
||||||
|
|
||||||
import { OperatorService, Permission } from 'app/core/core-services/operator.service';
|
import { OperatorService, Permission } from 'app/core/core-services/operator.service';
|
||||||
import { ConfigService } from 'app/core/ui-services/config.service';
|
import { ConfigService } from 'app/core/ui-services/config.service';
|
||||||
@ -13,7 +13,10 @@ const STREAM_RUNNING_STORAGE_KEY = 'streamIsRunning';
|
|||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class StreamService {
|
export class StreamService {
|
||||||
public liveStreamUrlObservable: Observable<string>;
|
public liveStreamUrlObservable: Observable<string> = this.configService.get<string>('general_system_stream_url');
|
||||||
|
public hasLiveStreamUrlObvervable: Observable<boolean> = this.liveStreamUrlObservable.pipe(
|
||||||
|
map(url => !!url?.trim() || false)
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* undefined is controlled behavior, meaning, this property was not
|
* undefined is controlled behavior, meaning, this property was not
|
||||||
@ -28,9 +31,11 @@ export class StreamService {
|
|||||||
private canSeeLiveStreamSubject = new Subject<boolean>();
|
private canSeeLiveStreamSubject = new Subject<boolean>();
|
||||||
public canSeeLiveStreamObservable = this.canSeeLiveStreamSubject.asObservable();
|
public canSeeLiveStreamObservable = this.canSeeLiveStreamSubject.asObservable();
|
||||||
|
|
||||||
public constructor(private storageMap: StorageMap, operator: OperatorService, configService: ConfigService) {
|
public constructor(
|
||||||
this.liveStreamUrlObservable = configService.get<string>('general_system_stream_url');
|
private storageMap: StorageMap,
|
||||||
|
operator: OperatorService,
|
||||||
|
private configService: ConfigService
|
||||||
|
) {
|
||||||
this.streamLoadedOnceObservable = this.storageMap
|
this.streamLoadedOnceObservable = this.storageMap
|
||||||
.watch(STREAM_RUNNING_STORAGE_KEY, { type: 'boolean' })
|
.watch(STREAM_RUNNING_STORAGE_KEY, { type: 'boolean' })
|
||||||
.pipe(distinctUntilChanged());
|
.pipe(distinctUntilChanged());
|
||||||
|
Loading…
Reference in New Issue
Block a user