mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-08 17:06:15 -08:00
Merge pull request #666 from 4gray/feat-extract-channel-item-add-epg-dialog
feat(ui): extract channel list item template and add EPG dialog
This commit is contained in:
3 files changed
+128
-62
No files matched your search
+80
@@ -0,0 +1,80 @@
|
||||
<div
|
||||
class="channel-list-item"
|
||||
[class.compact]="!showEpg"
|
||||
cdkDrag
|
||||
[cdkDragDisabled]="!isDraggable"
|
||||
cdkDragPreviewContainer="parent"
|
||||
[class.active]="selected"
|
||||
(click)="clicked.emit()"
|
||||
data-test-id="channel-item"
|
||||
>
|
||||
@if (isDraggable) {
|
||||
<mat-icon cdkDragHandle class="drag-icon">drag_indicator</mat-icon>
|
||||
}
|
||||
<div class="channel-content">
|
||||
@if (logo) {
|
||||
<img
|
||||
class="channel-logo"
|
||||
[src]="logo"
|
||||
onerror="this.style.display='none'"
|
||||
alt="Channel Logo"
|
||||
/>
|
||||
}
|
||||
<div class="channel-details">
|
||||
<div class="channel-name">{{ name }}</div>
|
||||
@if (showEpg) {
|
||||
<div class="epg-container">
|
||||
<div class="epg-content">
|
||||
@if (epgProgram) {
|
||||
<div class="epg-title">
|
||||
{{ epgProgram.title?.[0]?.value }}
|
||||
</div>
|
||||
<div class="epg-timeline">
|
||||
<span class="epg-time"
|
||||
>{{ formatTime(epgProgram.start) }} -
|
||||
{{ formatTime(epgProgram.stop) }}</span
|
||||
>
|
||||
<div class="epg-progress-track">
|
||||
<div
|
||||
class="epg-progress-fill"
|
||||
[ngStyle]="{
|
||||
width: progressPercentage + '%',
|
||||
}"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
} @else {
|
||||
<div class="epg-placeholder">
|
||||
{{ 'EPG.NO_PROGRAM_INFO' | translate }}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
@if (epgProgram) {
|
||||
<button
|
||||
mat-icon-button
|
||||
class="program-info-button"
|
||||
[matTooltip]="
|
||||
'EPG.PROGRAM_DIALOG.SHOW_PROGRAM_DETAILS'
|
||||
| translate
|
||||
"
|
||||
(click)="showProgramDescription(epgProgram, $event)"
|
||||
>
|
||||
<mat-icon>info</mat-icon>
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
@if (showFavoriteButton) {
|
||||
<button
|
||||
mat-icon-button
|
||||
class="favorite-button"
|
||||
color="primary"
|
||||
[matTooltip]="'CHANNELS.REMOVE_FAVORITE' | translate"
|
||||
(click)="favoriteToggled.emit($event)"
|
||||
>
|
||||
<mat-icon color="accent">star</mat-icon>
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
+31
@@ -1,5 +1,6 @@
|
||||
// Main channel list item container
|
||||
.channel-list-item {
|
||||
width: 360px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 68px;
|
||||
@@ -75,6 +76,7 @@
|
||||
gap: 2px;
|
||||
flex: 1;
|
||||
min-width: 0; // Allow text truncation
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
// Channel name
|
||||
@@ -90,6 +92,25 @@
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
// EPG container - holds EPG content and info button
|
||||
.epg-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
width: 100%;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
// EPG content area
|
||||
.epg-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
overflow: hidden; // Allow text truncation within content
|
||||
}
|
||||
|
||||
// EPG title (program name)
|
||||
.epg-title {
|
||||
font-family:
|
||||
@@ -168,3 +189,13 @@
|
||||
.favorite-button {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
// Program info button
|
||||
.program-info-button {
|
||||
flex-shrink: 0;
|
||||
opacity: 0.7;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
+17
-62
@@ -1,5 +1,5 @@
|
||||
import { DragDropModule } from '@angular/cdk/drag-drop';
|
||||
import { NgIf, NgStyle } from '@angular/common';
|
||||
import { NgStyle } from '@angular/common';
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
@@ -14,87 +14,30 @@ import {
|
||||
SimpleChanges,
|
||||
} from '@angular/core';
|
||||
import { MatIconButton } from '@angular/material/button';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { MatIcon } from '@angular/material/icon';
|
||||
import { MatListModule } from '@angular/material/list';
|
||||
import { MatTooltip } from '@angular/material/tooltip';
|
||||
import { TranslatePipe } from '@ngx-translate/core';
|
||||
import { EpgProgram } from 'shared-interfaces';
|
||||
import { EpgItemDescriptionComponent } from '../../epg-list/epg-item-description/epg-item-description.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-channel-list-item',
|
||||
styleUrls: ['./channel-list-item.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
template: `<div
|
||||
class="channel-list-item"
|
||||
[class.compact]="!showEpg"
|
||||
cdkDrag
|
||||
[cdkDragDisabled]="!isDraggable"
|
||||
cdkDragPreviewContainer="parent"
|
||||
[class.active]="selected"
|
||||
(click)="clicked.emit()"
|
||||
data-test-id="channel-item"
|
||||
>
|
||||
<mat-icon
|
||||
*ngIf="isDraggable"
|
||||
cdkDragHandle
|
||||
class="drag-icon"
|
||||
>drag_indicator</mat-icon
|
||||
>
|
||||
<div class="channel-content">
|
||||
<img
|
||||
class="channel-logo"
|
||||
*ngIf="logo"
|
||||
[src]="logo"
|
||||
onerror="this.style.display='none'"
|
||||
alt="Channel Logo"
|
||||
/>
|
||||
<div class="channel-details">
|
||||
<div class="channel-name">{{ name }}</div>
|
||||
@if (showEpg) {
|
||||
@if (epgProgram) {
|
||||
<div class="epg-title">
|
||||
{{ epgProgram.title?.[0]?.value }}
|
||||
</div>
|
||||
<div class="epg-timeline">
|
||||
<span class="epg-time">{{ formatTime(epgProgram.start) }} - {{ formatTime(epgProgram.stop) }}</span>
|
||||
<div class="epg-progress-track">
|
||||
<div
|
||||
class="epg-progress-fill"
|
||||
[ngStyle]="{ width: progressPercentage + '%' }"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
} @else {
|
||||
<div class="epg-placeholder">
|
||||
{{ 'EPG.NO_PROGRAM_INFO' | translate }}
|
||||
</div>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
*ngIf="showFavoriteButton"
|
||||
mat-icon-button
|
||||
class="favorite-button"
|
||||
color="primary"
|
||||
[matTooltip]="'CHANNELS.REMOVE_FAVORITE' | translate"
|
||||
(click)="favoriteToggled.emit($event)"
|
||||
>
|
||||
<mat-icon color="accent">star</mat-icon>
|
||||
</button>
|
||||
</div>`,
|
||||
templateUrl: './channel-list-item.component.html',
|
||||
imports: [
|
||||
DragDropModule,
|
||||
MatIcon,
|
||||
MatIconButton,
|
||||
MatTooltip,
|
||||
NgIf,
|
||||
NgStyle,
|
||||
TranslatePipe,
|
||||
],
|
||||
})
|
||||
export class ChannelListItemComponent implements OnInit, OnChanges, OnDestroy {
|
||||
private readonly cdr = inject(ChangeDetectorRef);
|
||||
private readonly dialog = inject(MatDialog);
|
||||
|
||||
@Input() isDraggable = false;
|
||||
@Input() logo!: string;
|
||||
@@ -165,4 +108,16 @@ export class ChannelListItemComponent implements OnInit, OnChanges, OnDestroy {
|
||||
hour12: false,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the dialog with details about the current EPG program
|
||||
* @param program EPG program to show details for
|
||||
* @param event Mouse event to stop propagation
|
||||
*/
|
||||
showProgramDescription(program: EpgProgram, event: MouseEvent): void {
|
||||
event.stopPropagation();
|
||||
this.dialog.open(EpgItemDescriptionComponent, {
|
||||
data: program,
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user