mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-10 10:06:15 -08:00
feat(multi-epg): only show channels from current playlist in multi-epg view
This commit is contained in:
1 parent
fb650b2bdd
commit
4193a67db3
4 files changed
+344
-203
No files matched your search
@@ -24,24 +24,34 @@
|
||||
<div class="today-date">
|
||||
{{ today | momentDate: 'YYYYMMDD' : 'MMMM Do, dddd' }}
|
||||
</div>
|
||||
<button mat-icon-button (click)="zoomIn()" [disabled]="hourWidth >= 800">
|
||||
<button mat-icon-button (click)="zoomIn()" [disabled]="(hourWidth$ | async) >= 800">
|
||||
<mat-icon>zoom_in</mat-icon>
|
||||
</button>
|
||||
<button mat-icon-button [disabled]="hourWidth <= 50" (click)="zoomOut()">
|
||||
<button mat-icon-button [disabled]="(hourWidth$ | async) <= 50" (click)="zoomOut()">
|
||||
<mat-icon>zoom_out</mat-icon>
|
||||
</button>
|
||||
<button
|
||||
mat-button
|
||||
[disabled]="channelsLowerRange === 0"
|
||||
(click)="previousChannels()"
|
||||
>
|
||||
Previous channels
|
||||
</button>
|
||||
<button mat-button (click)="nextChannels()">Next channels</button>
|
||||
<div class="navigation-buttons">
|
||||
<button
|
||||
mat-button
|
||||
(click)="previousChannels()"
|
||||
[disabled]="channelsLowerRange === 0"
|
||||
matTooltip="Previous channels"
|
||||
>
|
||||
<mat-icon>keyboard_arrow_up</mat-icon> Previous channels
|
||||
</button>
|
||||
<button
|
||||
mat-button
|
||||
(click)="nextChannels()"
|
||||
[disabled]="isLastPage"
|
||||
matTooltip="Next channels"
|
||||
>
|
||||
<mat-icon>keyboard_arrow_down</mat-icon> Next channels
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="parent" #epgContainer>
|
||||
<svg id="channels-column">
|
||||
<g *ngFor="let item of channels; let i = index">
|
||||
<g *ngFor="let item of channels$ | async; let i = index; trackBy: trackByIndex">
|
||||
<!-- channel name -->
|
||||
<g class="channel">
|
||||
<rect
|
||||
@@ -49,96 +59,78 @@
|
||||
[attr.height]="barHeight"
|
||||
[attr.y]="barHeight * i + barHeight"
|
||||
stroke="black"
|
||||
></rect>
|
||||
@if (item.icon) {
|
||||
<image
|
||||
[attr.y]="barHeight * i + barHeight + 1"
|
||||
[attr.href]="item.icon"
|
||||
[attr.height]="barHeight - 2"
|
||||
width="100"
|
||||
[matTooltip]="item.name"
|
||||
></image>
|
||||
}
|
||||
@if (!item.icon) {
|
||||
<foreignObject
|
||||
[attr.y]="barHeight * i + barHeight"
|
||||
width="100"
|
||||
[attr.height]="barHeight"
|
||||
>
|
||||
<div class="channel-name">
|
||||
{{ item.name }}
|
||||
</div>
|
||||
</foreignObject>
|
||||
}
|
||||
/>
|
||||
<foreignObject
|
||||
width="100"
|
||||
[attr.height]="barHeight"
|
||||
[attr.y]="barHeight * i + barHeight"
|
||||
>
|
||||
<div class="channel-name">
|
||||
<img
|
||||
*ngIf="item.icon"
|
||||
[src]="item.icon"
|
||||
[alt]="item.name"
|
||||
style="height: 20px; width: 20px; margin-right: 8px;"
|
||||
>
|
||||
<span>{{ item.name }}</span>
|
||||
</div>
|
||||
</foreignObject>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
<div id="epg-container">
|
||||
<svg [attr.width]="24 * hourWidth" height="100%" id="epg-svg">
|
||||
<svg [attr.width]="(hourWidth$ | async) * 24" height="100%" id="epg-svg">
|
||||
<!-- time headline -->
|
||||
<g *ngFor="let a of timeHeader; let i = index">
|
||||
<g *ngFor="let hour of timeHeader; trackBy: trackByIndex">
|
||||
<rect
|
||||
[matTooltip]="i + ':00'"
|
||||
[attr.width]="hourWidth"
|
||||
[matTooltip]="hour + ':00'"
|
||||
[attr.width]="hourWidth$ | async"
|
||||
[attr.height]="barHeight"
|
||||
[attr.x]="i * hourWidth"
|
||||
[attr.x]="hour * (hourWidth$ | async)"
|
||||
fill="#000"
|
||||
></rect>
|
||||
<text
|
||||
[attr.x]="i * hourWidth"
|
||||
[attr.x]="hour * (hourWidth$ | async)"
|
||||
y="10"
|
||||
font-size="14"
|
||||
fill="white"
|
||||
transform="translate(20,20)"
|
||||
>
|
||||
{{ i }}:00
|
||||
{{ hour }}:00
|
||||
</text>
|
||||
</g>
|
||||
|
||||
<!-- epg channels with programs -->
|
||||
<g *ngFor="let item of channels; let i = index">
|
||||
<g *ngFor="let item of channels$ | async; let i = index; trackBy: trackByIndex">
|
||||
<g
|
||||
*ngFor="let program of item.programs; let a = index"
|
||||
[matTooltip]="program.title"
|
||||
class="program-item"
|
||||
*ngFor="let program of item.programs; trackBy: trackByProgram"
|
||||
[attr.transform]="'translate(' + program.startPosition + ',' + (barHeight * i + barHeight) + ')'"
|
||||
class="program"
|
||||
(click)="showDescription(program)"
|
||||
>
|
||||
<!-- program item -->
|
||||
<rect
|
||||
[attr.width]="program.width"
|
||||
[attr.height]="barHeight"
|
||||
[attr.x]="program.startPosition"
|
||||
[attr.y]="barHeight * i + barHeight"
|
||||
fill="#000"
|
||||
[matTooltip]="program.title"
|
||||
></rect>
|
||||
<foreignObject
|
||||
(click)="showDescription(program)"
|
||||
[attr.width]="program.width"
|
||||
[attr.height]="barHeight"
|
||||
[attr.y]="barHeight * i + barHeight"
|
||||
[attr.x]="program.startPosition"
|
||||
>
|
||||
<div
|
||||
[innerHtml]="program.title"
|
||||
class="program-name"
|
||||
></div>
|
||||
<div class="program-title">{{ program.title }}</div>
|
||||
</foreignObject>
|
||||
</g>
|
||||
<line
|
||||
[attr.x1]="0"
|
||||
[attr.y1]="barHeight * i + barHeight"
|
||||
[attr.x2]="24 * hourWidth"
|
||||
[attr.y2]="barHeight * i + barHeight"
|
||||
stroke="#676767"
|
||||
/>
|
||||
</g>
|
||||
|
||||
<!-- current time line -->
|
||||
<line
|
||||
[attr.x1]="currentTimeLine"
|
||||
[attr.y1]="barHeight"
|
||||
y1="0"
|
||||
[attr.x2]="currentTimeLine"
|
||||
id="current-time-line"
|
||||
y2="1000"
|
||||
stroke="black"
|
||||
/>
|
||||
[attr.y2]="(channels$ | async)?.length * barHeight + barHeight"
|
||||
stroke="red"
|
||||
stroke-width="2"
|
||||
></line>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
@@ -43,12 +43,42 @@ rect {
|
||||
width: 100px;
|
||||
flex: none;
|
||||
border-right: 2px solid #ccc;
|
||||
|
||||
.channel {
|
||||
cursor: pointer;
|
||||
|
||||
rect {
|
||||
fill: #2d2d2d;
|
||||
stroke: #3d3d3d;
|
||||
}
|
||||
|
||||
&:hover rect {
|
||||
fill: #3d3d3d;
|
||||
}
|
||||
}
|
||||
|
||||
.channel-name {
|
||||
color: white;
|
||||
padding: 4px 8px;
|
||||
font-size: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
image {
|
||||
object-fit: contain;
|
||||
background: #2d2d2d;
|
||||
}
|
||||
}
|
||||
|
||||
.channel-name {
|
||||
/* .channel-name {
|
||||
margin: 0 5px;
|
||||
text-align: center;
|
||||
}
|
||||
} */
|
||||
|
||||
#epg-navigation {
|
||||
display: flex;
|
||||
@@ -57,6 +87,31 @@ rect {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#epg-svg {
|
||||
.program {
|
||||
cursor: pointer;
|
||||
|
||||
rect {
|
||||
fill: #2d2d2d;
|
||||
stroke: #3d3d3d;
|
||||
}
|
||||
|
||||
&:hover rect {
|
||||
fill: #3d3d3d;
|
||||
}
|
||||
}
|
||||
|
||||
.program-title {
|
||||
color: white;
|
||||
padding: 4px 8px;
|
||||
font-size: 12px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
.today-date {
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
|
||||
@@ -2,10 +2,13 @@ import { OverlayRef } from '@angular/cdk/overlay';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import {
|
||||
AfterViewInit,
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
Component,
|
||||
ElementRef,
|
||||
Inject,
|
||||
NgZone,
|
||||
Input,
|
||||
OnDestroy,
|
||||
OnInit,
|
||||
ViewChild,
|
||||
} from '@angular/core';
|
||||
@@ -14,18 +17,27 @@ import { MatDialog } from '@angular/material/dialog';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { addDays, differenceInMinutes, format, parse, subDays } from 'date-fns';
|
||||
import {
|
||||
EPG_GET_CHANNELS_BY_RANGE,
|
||||
EPG_GET_CHANNELS_BY_RANGE_RESPONSE,
|
||||
} from '../../../../../shared/ipc-commands';
|
||||
import { DataService } from '../../../services/data.service';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { Channel } from '../../../../../shared/channel.interface';
|
||||
import { MomentDatePipe } from '../../../shared/pipes/moment-date.pipe';
|
||||
import { EpgChannel } from '../../models/epg-channel.model';
|
||||
import { EpgProgram } from '../../models/epg-program.model';
|
||||
import { EpgItemDescriptionComponent } from '../epg-list/epg-item-description/epg-item-description.component';
|
||||
import { COMPONENT_OVERLAY_REF } from '../video-player/video-player.component';
|
||||
|
||||
interface EnrichedProgram extends EpgProgram {
|
||||
startDate: Date;
|
||||
stopDate: Date;
|
||||
startPosition: number;
|
||||
width: number;
|
||||
}
|
||||
|
||||
interface EnrichedChannel extends EpgChannel {
|
||||
programs: EnrichedProgram[];
|
||||
}
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
imports: [
|
||||
@@ -39,182 +51,242 @@ import { COMPONENT_OVERLAY_REF } from '../video-player/video-player.component';
|
||||
selector: 'app-multi-epg-container',
|
||||
templateUrl: './multi-epg-container.component.html',
|
||||
styleUrls: ['./multi-epg-container.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class MultiEpgContainerComponent implements OnInit, AfterViewInit {
|
||||
export class MultiEpgContainerComponent
|
||||
implements OnInit, AfterViewInit, OnDestroy
|
||||
{
|
||||
@ViewChild('epgContainer') epgContainer: ElementRef;
|
||||
timeHeader = new Array(24);
|
||||
hourWidth = 150;
|
||||
barHeight = 50;
|
||||
originalEpgData: (EpgChannel & { programs: EpgProgram[] })[] = [];
|
||||
channels: (EpgChannel & { programs: EpgProgram[] })[] = [];
|
||||
|
||||
@Input() set playlistChannels(value: Observable<Channel[]>) {
|
||||
if (value) {
|
||||
value.subscribe((channels) => {
|
||||
this._playlistChannels = channels;
|
||||
this.initializeVisibleChannels();
|
||||
this.requestPrograms();
|
||||
});
|
||||
}
|
||||
}
|
||||
private _playlistChannels: Channel[] = [];
|
||||
|
||||
readonly timeHeader = Array.from({ length: 24 }, (_, i) => i);
|
||||
readonly hourWidth$ = new BehaviorSubject<number>(150);
|
||||
readonly barHeight = 50;
|
||||
|
||||
channels$ = new BehaviorSubject<EnrichedChannel[]>([]);
|
||||
today = format(new Date(), 'yyyyMMdd');
|
||||
currentTimeLine = 0;
|
||||
visibleChannels;
|
||||
visibleChannels = 20;
|
||||
channelsLowerRange = 0;
|
||||
channelsUpperRange;
|
||||
channelsUpperRange = this.visibleChannels;
|
||||
originalEpgData: any[] = [];
|
||||
|
||||
private dateCache = new Map<string, Date>();
|
||||
private interval: any;
|
||||
|
||||
isLastPage = false;
|
||||
totalChannels = 0;
|
||||
|
||||
constructor(
|
||||
private dataService: DataService,
|
||||
private dialog: MatDialog,
|
||||
private ngZone: NgZone,
|
||||
private cdr: ChangeDetectorRef,
|
||||
@Inject(COMPONENT_OVERLAY_REF) private overlayRef: OverlayRef
|
||||
) {
|
||||
this.dataService.listenOn(
|
||||
EPG_GET_CHANNELS_BY_RANGE_RESPONSE,
|
||||
(event, response) =>
|
||||
this.ngZone.run(() => {
|
||||
if (response) {
|
||||
this.originalEpgData = response.payload;
|
||||
this.channels = this.enrichProgramData();
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
ngOnInit() {
|
||||
this.calculateCurrentTimeBar();
|
||||
this.interval = setInterval(() => {
|
||||
this.calculateCurrentTimeBar();
|
||||
}, 60000);
|
||||
}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
this.initializeVisibleChannels();
|
||||
this.scrollToCurrentTime();
|
||||
}
|
||||
|
||||
private scrollToCurrentTime(): void {
|
||||
const timeNow = new Date();
|
||||
const scrollPosition =
|
||||
(timeNow.getHours() + timeNow.getMinutes() / 60) * this.hourWidth;
|
||||
document
|
||||
.getElementById('epg-container')!
|
||||
.scrollTo(scrollPosition < 1000 ? 0 : scrollPosition - 150, 0);
|
||||
(timeNow.getHours() + timeNow.getMinutes() / 60) *
|
||||
this.hourWidth$.value;
|
||||
|
||||
const borderInPx =
|
||||
this.epgContainer.nativeElement.offsetHeight / this.barHeight;
|
||||
this.visibleChannels = Math.floor(
|
||||
(this.epgContainer.nativeElement.offsetHeight - borderInPx) /
|
||||
this.barHeight -
|
||||
1
|
||||
);
|
||||
this.channelsUpperRange = this.visibleChannels;
|
||||
this.requestPrograms();
|
||||
requestAnimationFrame(() => {
|
||||
const container = document.getElementById('epg-container');
|
||||
if (container) {
|
||||
container.scrollTo(scrollPosition < 1000 ? 0 : scrollPosition - 150, 0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private initializeVisibleChannels(): void {
|
||||
if (this.epgContainer) {
|
||||
const containerHeight = this.epgContainer.nativeElement.offsetHeight;
|
||||
const calculatedVisibleChannels = Math.floor((containerHeight - this.barHeight) / this.barHeight);
|
||||
|
||||
this.visibleChannels = Math.max(10, Math.min(calculatedVisibleChannels, 20));
|
||||
this.channelsUpperRange = this.visibleChannels;
|
||||
|
||||
console.log('Container height:', containerHeight);
|
||||
console.log('Calculated visible channels:', this.visibleChannels);
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.hourWidth$.complete();
|
||||
this.channels$.complete();
|
||||
clearInterval(this.interval);
|
||||
}
|
||||
|
||||
trackByIndex(index: number): number {
|
||||
return index;
|
||||
}
|
||||
|
||||
trackByProgram(_: number, program: EnrichedProgram): string {
|
||||
return program.start + program.title;
|
||||
}
|
||||
|
||||
async requestPrograms(): Promise<void> {
|
||||
const today = new Date();
|
||||
const startTime = format(subDays(today, 1), 'yyyyMMddHHmmss +0000');
|
||||
const endTime = format(addDays(today, 2), 'yyyyMMddHHmmss +0000');
|
||||
|
||||
try {
|
||||
const channelNames = this._playlistChannels
|
||||
.map((channel) => channel.name?.trim() ?? '')
|
||||
.filter((name) => name !== '');
|
||||
|
||||
console.log('Requesting EPG data:');
|
||||
console.log('- Skip:', this.channelsLowerRange);
|
||||
console.log('- Limit:', this.visibleChannels);
|
||||
console.log('- Channel names count:', channelNames.length);
|
||||
|
||||
const response = await invoke<any>('get_epg_by_range', {
|
||||
startTime,
|
||||
endTime,
|
||||
skip: this.channelsLowerRange,
|
||||
limit: this.visibleChannels,
|
||||
playlistChannelNames: channelNames,
|
||||
});
|
||||
|
||||
if (response) {
|
||||
console.log('Received channels:', response.length);
|
||||
this.originalEpgData = response;
|
||||
this.channels$.next(this.enrichProgramData());
|
||||
|
||||
// Update isLastPage based on the number of channels received
|
||||
this.isLastPage = response.length < this.visibleChannels;
|
||||
|
||||
this.cdr.detectChanges();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching EPG data:', error);
|
||||
}
|
||||
}
|
||||
|
||||
nextChannels(): void {
|
||||
this.channelsLowerRange = this.channelsUpperRange;
|
||||
this.channelsUpperRange =
|
||||
this.channelsUpperRange + this.visibleChannels;
|
||||
this.channels = [];
|
||||
console.log('Next channels clicked');
|
||||
console.log('Current range:', this.channelsLowerRange, 'to', this.channelsUpperRange);
|
||||
|
||||
this.channelsLowerRange += this.visibleChannels;
|
||||
this.channelsUpperRange = this.channelsLowerRange + this.visibleChannels;
|
||||
|
||||
console.log('New range:', this.channelsLowerRange, 'to', this.channelsUpperRange);
|
||||
this.requestPrograms();
|
||||
}
|
||||
|
||||
previousChannels(): void {
|
||||
this.channelsUpperRange =
|
||||
this.channelsUpperRange - this.visibleChannels;
|
||||
this.channelsLowerRange =
|
||||
this.channelsUpperRange - this.visibleChannels;
|
||||
|
||||
console.log('Previous channels clicked');
|
||||
console.log('Current range:', this.channelsLowerRange, 'to', this.channelsUpperRange);
|
||||
|
||||
this.channelsLowerRange = Math.max(0, this.channelsLowerRange - this.visibleChannels);
|
||||
this.channelsUpperRange = this.channelsLowerRange + this.visibleChannels;
|
||||
|
||||
console.log('New range:', this.channelsLowerRange, 'to', this.channelsUpperRange);
|
||||
this.requestPrograms();
|
||||
}
|
||||
|
||||
requestPrograms() {
|
||||
this.dataService.sendIpcEvent(EPG_GET_CHANNELS_BY_RANGE, {
|
||||
limit: this.channelsUpperRange,
|
||||
skip: this.channelsLowerRange,
|
||||
});
|
||||
private getCachedDate(dateStr: string): Date {
|
||||
let date = this.dateCache.get(dateStr);
|
||||
if (!date) {
|
||||
date = new Date(dateStr);
|
||||
this.dateCache.set(dateStr, date);
|
||||
}
|
||||
return date;
|
||||
}
|
||||
|
||||
enrichProgramData() {
|
||||
private enrichProgramData(): EnrichedChannel[] {
|
||||
const hourWidth = this.hourWidth$.value;
|
||||
|
||||
return this.originalEpgData.map((channel) => {
|
||||
const filteredPrograms = channel.programs
|
||||
.filter((item) => {
|
||||
const itemDate = format(
|
||||
this.getCachedDate(item.start),
|
||||
'yyyyMMdd'
|
||||
);
|
||||
return itemDate === this.today;
|
||||
})
|
||||
.map((program) => {
|
||||
const startDate = this.getCachedDate(program.start);
|
||||
const stopDate = this.getCachedDate(program.stop);
|
||||
const startPosition =
|
||||
(startDate.getHours() + startDate.getMinutes() / 60) *
|
||||
hourWidth;
|
||||
const duration = differenceInMinutes(stopDate, startDate);
|
||||
const width = (duration * hourWidth) / 60;
|
||||
|
||||
return {
|
||||
...program,
|
||||
startDate,
|
||||
stopDate,
|
||||
startPosition,
|
||||
width,
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
...channel,
|
||||
programs: channel.programs
|
||||
.filter((item) => item.start.includes(this.today))
|
||||
.map((program) => {
|
||||
const startDate = parse(
|
||||
program.start,
|
||||
'yyyyMMddHHmmss XXXX',
|
||||
addDays(new Date(), 1)
|
||||
);
|
||||
const stopDate = parse(
|
||||
program.stop,
|
||||
'yyyyMMddHHmmss XXXX',
|
||||
addDays(new Date(), 1)
|
||||
);
|
||||
return {
|
||||
...program,
|
||||
startDate,
|
||||
stopDate,
|
||||
startPosition: this.positionToStartInPx(startDate),
|
||||
width: this.programDurationInPx(
|
||||
startDate,
|
||||
stopDate
|
||||
),
|
||||
};
|
||||
}),
|
||||
programs: filteredPrograms,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
positionToStartInPx(startDate: Date) {
|
||||
return (
|
||||
(startDate.getHours() + startDate.getMinutes() / 60) *
|
||||
this.hourWidth
|
||||
);
|
||||
}
|
||||
|
||||
programDurationInPx(startDate: Date, stopDate: Date) {
|
||||
const duration = differenceInMinutes(stopDate, startDate);
|
||||
return (duration * this.hourWidth) / 60;
|
||||
}
|
||||
|
||||
recalculate(): void {
|
||||
this.channels.forEach((channel) => {
|
||||
channel.programs = channel.programs.map((program: any) => {
|
||||
return {
|
||||
...program,
|
||||
startPosition: this.positionToStartInPx(program.startDate),
|
||||
width: this.programDurationInPx(
|
||||
program.startDate,
|
||||
program.stopDate
|
||||
),
|
||||
};
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
zoomIn(): void {
|
||||
this.hourWidth += 50;
|
||||
this.recalculate();
|
||||
if (this.hourWidth$.value >= 800) return;
|
||||
this.hourWidth$.next(this.hourWidth$.value + 50);
|
||||
this.channels$.next(this.enrichProgramData());
|
||||
this.calculateCurrentTimeBar();
|
||||
this.cdr.detectChanges();
|
||||
}
|
||||
|
||||
zoomOut(): void {
|
||||
if (this.hourWidth <= 50) return;
|
||||
this.hourWidth -= 50;
|
||||
this.recalculate();
|
||||
if (this.hourWidth$.value <= 50) return;
|
||||
this.hourWidth$.next(this.hourWidth$.value - 50);
|
||||
this.channels$.next(this.enrichProgramData());
|
||||
this.calculateCurrentTimeBar();
|
||||
this.cdr.detectChanges();
|
||||
}
|
||||
|
||||
calculateCurrentTimeBar(): void {
|
||||
const timeNow = new Date();
|
||||
this.currentTimeLine =
|
||||
(timeNow.getHours() + timeNow.getMinutes() / 60) * this.hourWidth;
|
||||
(new Date().getHours() + new Date().getMinutes() / 60) *
|
||||
this.hourWidth$.value;
|
||||
this.cdr.detectChanges();
|
||||
}
|
||||
|
||||
switchDay(direction: 'prev' | 'next'): void {
|
||||
const currentDate = parse(this.today, 'yyyyMMdd', new Date());
|
||||
this.today =
|
||||
direction === 'prev'
|
||||
? format(
|
||||
subDays(parse(this.today, 'yyyyMMdd', new Date()), 1),
|
||||
'yyyyMMdd'
|
||||
)
|
||||
: format(
|
||||
addDays(parse(this.today, 'yyyyMMdd', new Date()), 1),
|
||||
'yyyyMMdd'
|
||||
);
|
||||
? format(subDays(currentDate, 1), 'yyyyMMdd')
|
||||
: format(addDays(currentDate, 1), 'yyyyMMdd');
|
||||
|
||||
this.calculateCurrentTimeBar();
|
||||
this.channels = this.enrichProgramData();
|
||||
this.channels$.next(this.enrichProgramData());
|
||||
this.cdr.detectChanges();
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the dialog with details about the selected program
|
||||
* @param program selected epg program
|
||||
*/
|
||||
showDescription(program: EpgProgram): void {
|
||||
this.dialog.open(EpgItemDescriptionComponent, {
|
||||
data: program,
|
||||
|
||||
@@ -266,20 +266,42 @@ export class VideoPlayerComponent implements OnInit, OnDestroy {
|
||||
/**
|
||||
* Opens the overlay with multi EPG view
|
||||
*/
|
||||
openMultiEpgView() {
|
||||
this.overlayRef = this.overlay.create();
|
||||
openMultiEpgView(): void {
|
||||
const positionStrategy = this.overlay
|
||||
.position()
|
||||
.global()
|
||||
.centerHorizontally()
|
||||
.centerVertically();
|
||||
|
||||
this.overlayRef = this.overlay.create({
|
||||
hasBackdrop: true,
|
||||
positionStrategy,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
});
|
||||
|
||||
const injector = Injector.create({
|
||||
providers: [
|
||||
{ provide: COMPONENT_OVERLAY_REF, useValue: this.overlayRef },
|
||||
{
|
||||
provide: COMPONENT_OVERLAY_REF,
|
||||
useValue: this.overlayRef,
|
||||
},
|
||||
],
|
||||
});
|
||||
const componentPortal = new ComponentPortal(
|
||||
|
||||
const portal = new ComponentPortal(
|
||||
MultiEpgContainerComponent,
|
||||
undefined,
|
||||
null,
|
||||
injector
|
||||
);
|
||||
this.overlayRef.addPanelClass('epg-overlay');
|
||||
this.overlayRef.attach(componentPortal);
|
||||
|
||||
const componentRef = this.overlayRef.attach(portal);
|
||||
componentRef.instance.playlistChannels =
|
||||
this.store.select(selectChannels);
|
||||
|
||||
this.overlayRef.backdropClick().subscribe(() => {
|
||||
this.overlayRef.dispose();
|
||||
});
|
||||
}
|
||||
|
||||
openUrl(url: string) {
|
||||
|
||||
Reference in new issue
Block a user