From f3e96c0c49f154809a46e4625a6ae444b2316c1f Mon Sep 17 00:00:00 2001 From: 4gray Date: Sun, 28 Jun 2026 12:18:10 +0200 Subject: [PATCH] refactor(epg): extract epg list helpers --- .../src/lib/epg-list/epg-list.component.ts | 78 +++---------------- .../ui/epg/src/lib/epg-list/epg-list.utils.ts | 73 +++++++++++++++++ 2 files changed, 82 insertions(+), 69 deletions(-) create mode 100644 libs/ui/epg/src/lib/epg-list/epg-list.utils.ts diff --git a/libs/ui/epg/src/lib/epg-list/epg-list.component.ts b/libs/ui/epg/src/lib/epg-list/epg-list.component.ts index c220a9c49..890819a69 100644 --- a/libs/ui/epg/src/lib/epg-list/epg-list.component.ts +++ b/libs/ui/epg/src/lib/epg-list/epg-list.component.ts @@ -20,16 +20,22 @@ import { normalizeDateLocale } from '@iptvnator/pipes'; import { Store } from '@ngrx/store'; import { TranslatePipe, TranslateService } from '@ngx-translate/core'; import { EpgActions, selectActive } from '@iptvnator/m3u-state'; -import { format, subDays } from 'date-fns'; +import { subDays } from 'date-fns'; import { startWith } from 'rxjs'; import { Channel, EpgChannel, EpgProgram } from '@iptvnator/shared/interfaces'; import { - EPG_DATE_KEY_FORMAT, EpgDateNavigationDirection, getTodayEpgDateKey, shiftEpgDateKey, } from '../epg-date'; import { EpgListItemComponent } from './epg-list-item/epg-list-item.component'; +import { + areProgramsSame, + buildScrollContextKey, + getProgramDateKey, + getProgramTimeMs, + trackProgram, +} from './epg-list.utils'; export interface EpgProgramActivationEvent { program: EpgProgram; @@ -62,6 +68,7 @@ export class EpgListComponent { readonly showDateNavigator = input(true); readonly programActivated = output(); readonly selectedDateChange = output(); + readonly trackProgram = trackProgram; private readonly store = inject(Store); private readonly epgService = inject(EpgService); @@ -241,19 +248,6 @@ export class EpgListComponent { this.activateProgram(program); } - trackProgram(index: number, program: EpgProgram): string { - const start = getProgramTimeMs(program.start, program.startTimestamp); - const stop = getProgramTimeMs(program.stop, program.stopTimestamp); - - return [ - program.channel ?? '', - Number.isFinite(start) ? start : program.start, - Number.isFinite(stop) ? stop : program.stop, - program.title ?? '', - index, - ].join('|'); - } - canActivateProgram(program: EpgProgram): boolean { return ( this.isProgramPlaying(program) || @@ -384,57 +378,3 @@ export class EpgListComponent { } } } - -function buildScrollContextKey( - channel: Channel | null, - programs: EpgProgram[] -): string | null { - if (!channel && programs.length === 0) { - return null; - } - - const channelKey = - channel?.tvg?.id || channel?.name || channel?.url || 'unknown-channel'; - const programKey = programs - .map( - (program) => - `${getProgramTimeMs(program.start, program.startTimestamp)}-${getProgramTimeMs(program.stop, program.stopTimestamp)}` - ) - .join('|'); - - return `${channelKey}:${programKey}`; -} - -function getProgramTimeMs( - isoValue: string, - timestampValue?: number | null -): number { - if (Number.isFinite(timestampValue) && Number(timestampValue) > 0) { - return Number(timestampValue) * 1000; - } - - return Date.parse(isoValue); -} - -function getProgramDateKey( - isoValue: string, - timestampValue?: number | null -): string { - const programTimeMs = getProgramTimeMs(isoValue, timestampValue); - - if (!Number.isFinite(programTimeMs)) { - return ''; - } - - return format(new Date(programTimeMs), EPG_DATE_KEY_FORMAT); -} - -function areProgramsSame(left: EpgProgram, right: EpgProgram): boolean { - return ( - (left.channel ?? '') === (right.channel ?? '') && - getProgramTimeMs(left.start, left.startTimestamp) === - getProgramTimeMs(right.start, right.startTimestamp) && - getProgramTimeMs(left.stop, left.stopTimestamp) === - getProgramTimeMs(right.stop, right.stopTimestamp) - ); -} diff --git a/libs/ui/epg/src/lib/epg-list/epg-list.utils.ts b/libs/ui/epg/src/lib/epg-list/epg-list.utils.ts new file mode 100644 index 000000000..a901f6d30 --- /dev/null +++ b/libs/ui/epg/src/lib/epg-list/epg-list.utils.ts @@ -0,0 +1,73 @@ +import { format } from 'date-fns'; +import type { Channel, EpgProgram } from '@iptvnator/shared/interfaces'; +import { EPG_DATE_KEY_FORMAT } from '../epg-date'; + +export function trackProgram(index: number, program: EpgProgram): string { + const start = getProgramTimeMs(program.start, program.startTimestamp); + const stop = getProgramTimeMs(program.stop, program.stopTimestamp); + + return [ + program.channel ?? '', + Number.isFinite(start) ? start : program.start, + Number.isFinite(stop) ? stop : program.stop, + program.title ?? '', + index, + ].join('|'); +} + +export function buildScrollContextKey( + channel: Channel | null, + programs: EpgProgram[] +): string | null { + if (!channel && programs.length === 0) { + return null; + } + + const channelKey = + channel?.tvg?.id || channel?.name || channel?.url || 'unknown-channel'; + const programKey = programs + .map( + (program) => + `${getProgramTimeMs(program.start, program.startTimestamp)}-${getProgramTimeMs(program.stop, program.stopTimestamp)}` + ) + .join('|'); + + return `${channelKey}:${programKey}`; +} + +export function getProgramTimeMs( + isoValue: string, + timestampValue?: number | null +): number { + if (Number.isFinite(timestampValue) && Number(timestampValue) > 0) { + return Number(timestampValue) * 1000; + } + + return Date.parse(isoValue); +} + +export function getProgramDateKey( + isoValue: string, + timestampValue?: number | null +): string { + const programTimeMs = getProgramTimeMs(isoValue, timestampValue); + + if (!Number.isFinite(programTimeMs)) { + return ''; + } + + return format(new Date(programTimeMs), EPG_DATE_KEY_FORMAT); +} + +export function areProgramsSame( + left: EpgProgram, + right: EpgProgram +): boolean { + return ( + (left.channel ?? '') === (right.channel ?? '') && + getProgramTimeMs(left.start, left.startTimestamp) === + getProgramTimeMs(right.start, right.startTimestamp) && + getProgramTimeMs(left.stop, left.stopTimestamp) === + getProgramTimeMs(right.stop, right.stopTimestamp) + ); +}