feat(epg): epg program list with date navigation

This commit is contained in:
4gray committed 2021-02-05 00:09:00 +01:00
1 parent 4881ba8fe0
commit fdbe02b47e
4 files changed
+147 -76

No files matched your search

@@ -1,49 +1,87 @@
<ng-container *ngIf="channel; else noEpg">
<div fxFlex="80px" id="channel-info" fxLayoutAlign="row" fxLayoutGap="10px">
<div fxLayoutAlign="column" fxLayoutGap="10px">
<div fxFlex="48px" fxFlexAlign="center">
<!-- channel info panel -->
<div fxFlex="120px" id="channel-info" fxLayout="column">
<div fxFlex="79px" fxLayout="row" fxLayoutGap="10px">
<div
fxFlex="60px"
class="channel-icon"
fxLayoutAlign="center center"
>
<img *ngIf="channel?.icon" [src]="channel.icon" width="48" />
</div>
<div fxFlex="100">
<div class="channel-name">{{ channel?.name[0]?.value }}</div>
<ng-container>
<div class="playing-now">Playing now:</div>
<div class="epg-program-name">
{{
playingNow
? playingNow.title[0]?.value
: 'Live stream'
}}
</div>
</ng-container>
<div fxFlex="100" fxFlexAlign="center">
<div class="channel-name">
{{ channel?.name[0]?.value }}
</div>
<div class="program-name">
{{
playingNow ? playingNow.title[0]?.value : 'Live stream'
}}
</div>
</div>
</div>
<div fxFlex="40px" fxLayout="row" id="date-navigator">
<button
fxFlex="40px"
mat-icon-button
(click)="changeDate('prev')"
matTooltip="Previous day"
>
<mat-icon>chevron_left</mat-icon>
</button>
<span
class="selected-date"
fxFlex="100"
fxLayoutAlign="center center"
>
{{ dateToday | momentDate: 'YYYYMMDD':'MMMM Do dddd' }}</span
>
<button
fxFlex="40px"
mat-icon-button
(click)="changeDate('next')"
matTooltip="Next day"
>
<mat-icon>chevron_right</mat-icon>
</button>
</div>
</div>
<!-- program list -->
<mat-selection-list fxFlex [multiple]="false">
<mat-list-option
*ngFor="let item of items"
[value]="item"
[class.active]="timeNow >= item.start && timeNow <= item.stop"
(click)="
setEpgProgram(
item,
timeNow >= item.start && timeNow <= item.stop
)
"
>
<div matLine>
<span class="time">{{ item.start }} - {{ item.stop }}</span>
<span
*ngIf="timeNow >= item.start && timeNow <= item.stop"
class="live-badge"
>live</span
>
</div>
<p matLine>{{ item?.title[0]?.value }}</p>
<mat-divider></mat-divider>
</mat-list-option>
<ng-container *ngIf="items?.length > 0; else epgNotAvailable">
<mat-list-option
*ngFor="let item of items"
[value]="item"
[class.active]="timeNow >= item.start && timeNow <= item.stop"
(click)="
setEpgProgram(
item,
timeNow >= item.start && timeNow <= item.stop
)
"
>
<div matLine>
<span class="time">{{ item.start }} - {{ item.stop }}</span>
<span
*ngIf="timeNow >= item.start && timeNow <= item.stop"
class="live-badge"
>live</span
>
</div>
<p matLine>{{ item?.title[0]?.value }}</p>
<mat-divider></mat-divider>
</mat-list-option>
</ng-container>
<ng-template #epgNotAvailable>
<mat-list-option
>Ooops, EPG is not available for the selected
date</mat-list-option
>
</ng-template>
</mat-selection-list>
</ng-container>
<ng-template #noEpg>
<mat-list>
<mat-list-item>
@@ -12,10 +12,9 @@
.active {
border-bottom: 1px dashed #666;
background: linear-gradient(to top, #d2d2d2 0%, #d6d6d6 20%, rgba(255, 255, 255, 0) 100%)
}
.time, .playing-now {
.time {
color: #666;
border-bottom: 1px solid #ccc;
font-size: 0.8em;
@@ -23,29 +22,27 @@
margin-bottom: 5px;
}
.epg-program-name {
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
font-size: 0.9em;
}
#channel-info {
padding:10px;
border-bottom: 1px solid #ccc;
box-shadow: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23);
background-color: #ccc;
}
.channel-name {
font-weight: 800;
}
.channel-icon {
overflow: hidden;
}
mat-list {
height: calc(100vh - 110px);
overflow: auto;
.channel-name {
font-weight: 800;
}
.program-name {
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
font-size: 0.9em;
}
}
mat-selection-list {
@@ -60,4 +57,13 @@ mat-selection-list {
text-transform: uppercase;
margin-left: 6px;
font-size: 0.8em;
}
#date-navigator {
border-top: 1px solid #999;
.selected-date {
font-size: 0.9em;
color: #333;
}
}
@@ -2,12 +2,14 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { EpgListComponent, EpgData } from './epg-list.component';
import { MatListModule } from '@angular/material/list';
import { MockModule } from 'ng-mocks';
import { MockModule, MockPipe } from 'ng-mocks';
import { ElectronService } from '../../../services/electron.service';
import { ElectronServiceStub } from '../../../home/home.component.spec';
import * as moment from 'moment';
import { EPG_GET_PROGRAM_DONE } from '../../../shared/ipc-commands';
import { ChannelStore } from '../../../state';
import { MomentDatePipe } from '../../../shared/pipes/moment-date.pipe';
import { MatIconModule } from '@angular/material/icon';
describe('EpgListComponent', () => {
let component: EpgListComponent;
@@ -77,8 +79,8 @@ describe('EpgListComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [EpgListComponent],
imports: [MockModule(MatListModule)],
declarations: [EpgListComponent, MockPipe(MomentDatePipe)],
imports: [MockModule(MatIconModule), MockModule(MatListModule)],
providers: [
{ provide: ElectronService, useClass: ElectronServiceStub },
],
@@ -37,6 +37,8 @@ export class EpgListComponent {
/** Current time as formatted string */
timeNow: string;
selectedDate: string;
/**
* Creates an instance of EpgListComponent
* @param electronService
@@ -61,25 +63,11 @@ export class EpgListComponent {
*/
handleEpgData(programs: { payload: EpgData }): void {
if (programs.payload?.items?.length > 0) {
this.programs = programs;
this.timeNow = moment(Date.now()).format('HH:mm');
this.dateToday = moment(Date.now()).format('YYYYMMDD');
this.channel = programs.payload?.channel;
this.items = programs.payload?.items
.filter((item) =>
item.start.includes(this.dateToday.toString())
)
.map((program) => ({
...program,
start: moment(program.start, 'YYYYMMDDHHmm ZZ').format(
'HH:mm'
),
stop: moment(program.stop, 'YYYYMMDDHHmm ZZ').format(
'HH:mm'
),
}))
.sort((a, b) => {
return a.start.localeCompare(b.start);
});
this.items = this.selectPrograms(programs);
this.setPlayingNow();
} else {
@@ -88,6 +76,42 @@ export class EpgListComponent {
}
}
/**
* Selects the program based on the active date
* @param programs object with all available epg programs for the active channel
*/
selectPrograms(programs: { payload: EpgData }): EpgProgram[] {
return programs.payload?.items
.filter((item) => item.start.includes(this.dateToday.toString()))
.map((program) => ({
...program,
start: moment(program.start, 'YYYYMMDDHHmm ZZ').format('HH:mm'),
stop: moment(program.stop, 'YYYYMMDDHHmm ZZ').format('HH:mm'),
}))
.sort((a, b) => {
return a.start.localeCompare(b.start);
});
}
/**
* Changes the date to update the epg list with programs
* @param direction direction to switch
*/
changeDate(direction: 'next' | 'prev'): void {
let dateToSwitch;
if (direction === 'next') {
dateToSwitch = moment(this.dateToday, 'YYYYMMDD')
.add(1, 'days')
.format('YYYYMMDD');
} else if (direction === 'prev') {
dateToSwitch = moment(this.dateToday, 'YYYYMMDD')
.subtract(1, 'days')
.format('YYYYMMDD');
}
this.dateToday = dateToSwitch;
this.items = this.selectPrograms(this.programs);
}
/**
* Sets the playing now variable based on the current time
*/
@@ -99,7 +123,8 @@ export class EpgListComponent {
/**
* Sets the provided epg program as active and starts to play
* @param program
* @param program epg program to set
* @param isLive live stream flag
*/
setEpgProgram(program: EpgProgram, isLive?: boolean): void {
isLive