Commit Graph
41 Commits
Author SHA1 Message Date
4gray 08b868d6c1 test(electron): harden runtime boundary coverage (#1267)
Adds contract-focused regression coverage for the Electron HTTP server,
remote-control events, settings events, and managed download paths, and makes
Tier A coverage fail closed when instrumentation fails or a runtime-owning
production file disappears from a project or from the merged Istanbul report.

The old `coverage:ci` exited 0 despite a `Failed to collect coverage`
diagnostic: libs/m3u-state/src/lib/effects.ts was simply absent from the merged
map. All 30 Tier A reports are now required, the merged map covers 710 files,
and effects.ts is reported as 0/159 instead of silently disappearing.

Also fixes remote static-file path containment for encoded, malformed, NUL,
POSIX and Win32-style traversal inputs, with behavior-preserving testability
seams.

Statements 69.27% -> 69.54%; http-server.ts 0% -> 90.21%,
remote-control.events.ts 0% -> 96.55%, settings.events.ts 59.25% -> 96.29%.
2026-07-26 22:27:50 +02:00
StefanandClaude 2f8aee72df feat(xtream): add catch-up playback to favorites and recent tabs (#1166)
Enables Xtream catch-up/timeshift from the Favorites and Recent surfaces (per-playlist and global), not just Live TV, and adds start-over replay of the currently-airing programme. Carries tv_archive/tv_archive_duration through the favorites and recently-viewed DB projections and maps them onto UnifiedCollectionItem; tv_archive_duration is interpreted as days, matching live-stream-layout.controlledArchiveDays.

Closes #1138.

Co-authored-by: Claude <noreply@anthropic.com>
2026-07-19 06:38:19 +02:00
4grayandClaude Fable 5 a51c537bb2 fix(theme): make scrollbars follow the app theme instead of the OS color scheme (#1179)
On Windows with a light OS theme, scrollbars rendered light even when the
app was switched to dark. Two combined causes:

- The page never declared `color-scheme`, so Chromium colored native
  scrollbars from the OS preference. Declare `color-scheme: light` on html
  and flip it to `dark` via `html:has(> body.dark-theme)` plus the
  `.dark-theme` block itself.
- Scrollbar styling referenced `--mat-sys-*` tokens, which are never
  emitted by the current Material theme setup (mat.define-theme +
  all-component-themes does not produce system tokens). Those
  `scrollbar-color` declarations computed to `auto`, falling back to the
  native (light) scrollbar. Switch scrollbar styling to the `--app-muted-color`
  design token (defined for both themes), replace hardcoded white
  `rgba(255,255,255,.08)` thumbs, and add an explicit `scrollbar-color`
  where only `scrollbar-width: thin` was set.

Verified live in Electron via CDP in both themes: scrollbar-color resolves
and scrollbars render dark in dark theme regardless of the OS setting.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 17:24:49 +02:00
4grayandClaude Fable 5 57ba1977a1 test: close coverage gaps in persistence, portal stores, EPG, players, and E2E (#1124)
* test(db): cover playback positions, recently viewed, and connection migrations

Add specs for the previously untested persistence paths: playback-position
and recently-viewed operations (upsert/dedup/ordering/scoped deletes),
shared-database path-utils, createTables and the tolerant column/index
migrations incl. Xtream cache deduplication. Exposes createTables through
the existing __databaseConnectionTestHooks object.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* test(xtream): cover the Electron DB-first data source and favorites guards

Add specs for electron-xtream-data-source (DB-hit vs cold-cache paths,
concurrent request dedup, error propagation, full method delegation) and
extend the favorites feature spec with the invalid-input and
content-not-found guard paths.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* test(stalker): cover favorites and recent store features

Add specs for with-stalker-favorites and with-stalker-recent: payload
normalization and id/title fallbacks, series-mode category forcing, meta
sync dispatches, snackbar/callback side effects, and error paths.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* test(epg): cover archive/summary utils and the EPG worker service

Add specs for the pure catch-up window and summary-progress helpers shared
by the EPG panels, and for epg-worker.service: in-flight dedup by URL,
double-settle guard, progress-aware timeouts, worker lifecycle and error
broadcasting. Also settle an interrupted fetch in epg.events.spec that
caused "Cannot log after tests are done" in longer runs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* test(player): cover the VLC session service

Mirror the MPV session spec patterns for VLC: enqueue-command building and
RC response parsing, launch argv construction, instance reuse over the RC
socket, exit-code handling, and the retry-without-RC fallback.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* test(e2e): add downloads page and EPG timeline interaction coverage

Downloads: empty state without sources, and a full lifecycle - authorize a
folder via a stubbed native dialog, download from a local server, verify
the completed item and file on disk, remove it from the UI. Timeline: zoom
changes block widths and the on-air info affordance opens the programme
dialog with the correct title and watch-live action.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* test: split oversized specs to meet the file-size guideline

Address review feedback: extract shared drizzle mocks into
operations.test-helpers.ts and split the Electron data-source delegation
spec into delegation + user-data files. Pure reorganization - test counts
and assertions unchanged (29/13/10), all files now under 300 lines.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* test(e2e): wait for DB readiness before opening the downloads page

On slow CI runners (macOS) the renderer can query SQLite while the DB
worker is still creating tables, leaving the downloads page on its
skeleton state forever. Poll a playlist read until it succeeds before
navigating on a cold profile.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(build): exclude *.test-helpers.ts from the electron-backend app tsconfig

The new operations.test-helpers.ts uses jest globals and broke the webpack
build and tsc typecheck, which compile every non-spec file in the app.
Exclude the test-helpers pattern alongside the existing spec exclusions.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 15:45:06 +02:00
4grayandClaude Fable 5 1c710d69ef chore(cleanup): delete nine dead components, orphaned i18n keys and unused deps (#1116)
* chore(cleanup): delete nine dead components, orphaned i18n keys and unused deps

Removes verified-dead components (0 class/selector references outside
their own files): EpgListComponent (+ epg-list-item), EpgViewComponent,
LiveEpgPanelComponent, StalkerCollectionChannelsListComponent,
NavigationComponent, FilterSortMenuComponent, video-player
ToolbarComponent, PortalCollectionShellComponent and
LoadingOverlayComponent, together with their barrel exports.

Alive code extracted from the deleted trees:
- LiveEpgPanelSummary -> libs/ui/shared-portals/src/lib/live-epg-panel-summary.ts
- EpgProgramActivationEvent -> libs/ui/epg/src/lib/epg-program-activation-event.ts
- epg-list.utils.ts trimmed to the three timeline-used helpers and moved
  to libs/ui/epg/src/lib/epg-program.utils.ts
- epg-item-description/ moved up out of the deleted epg-list/ folder

Also removes 18 i18n keys now unused (from all 18 locales), dead CSS
selectors targeting the deleted elements, and unused dependencies:
lodash (+ @types/lodash), semver, @ngrx/component-store and
@videojs/http-streaming (videojs-quality-selector-hls declares no peer
dependency on it; video.js 8 bundles VHS).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* chore(coverage): move shared-portals to Tier C, fix stale doc references

The Tier A gate failed in CI because deleting the dead epg-view and
live-epg-panel components removed the only specs in libs/ui/shared-portals.
The lib now contains a single type-only interface (LiveEpgPanelSummary),
so there is no runtime code to unit test; reclassify it to Tier C with a
documented reason, matching the gate's own guidance.

Also update remaining doc references to the deleted components in
docs/architecture/stalker-epg.md, iptvnator-ui-guidelines.md and
CLAUDE.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 11:09:50 +02:00
4grayandClaude Opus 4.8 0b526b119a feat(epg): add vertical list view for the live EPG panel (#1115)
* feat(epg): add vertical list view for the live EPG panel

Add an EPG list view — a vertical, single-day programme list — as an
alternative rendering of the live EPG panel, selectable via a new
Settings → EPG → "Guide view" toggle (epgViewMode: 'timeline' | 'list',
default 'timeline' so existing users see no change).

- New EpgListViewComponent (app-epg-list-view) mirrors
  EpgTimelineComponent's input/output contract 1:1, so all four live
  hosts (M3U player, unified live tab, Xtream, Stalker) swap the panel
  with a plain @if and identical bindings.
- Reuses the shared view-agnostic EPG modules (classifyTimelineWhen,
  hasProgramsForDateKey, epg-archive.util catch-up gating,
  epg-summary.util collapsed-summary maths, epg-date helpers,
  EpgProgrammeDialogService, app-epg-timeline-empty-state) — no
  duplicated logic.
- Rows show time range, title, optional description, live progress on
  the on-air row, catch-up "Watch" on past rows when archive playback
  is available, and a details dialog; keyboard activation guards
  nested buttons (target === currentTarget).
- Auto-focuses the on-air row on channel select, restores it across
  collapse/expand remounts, and shows a sticky in-flow "On now" strip
  (never overlaying rows) when the current programme is scrolled away;
  all scroll maths is rect-based relative to the scroller.
- List mode raises only the inline panel height via an epg--list
  modifier (--epg-inline-height clamp); timeline and collapsed heights
  are unchanged.
- Setting flows end-to-end (Settings interface → DEFAULT_SETTINGS →
  SettingsStore/StorageMap → segmented control in the EPG section);
  Electron-only UI, PWA stays on the timeline default. i18n keys added
  to all 18 locales.
- Tests: new component/row/utils/scroll-controller specs, settings
  persistence spec, swap tests in all four host specs, and Electron
  E2E for the settings round-trip and the rendered list view. Docs
  updated (m3u-playlist-module.md).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(epg): address list-view review findings from Codex and Greptile

- Reset the list view to today when a new channel's programme set
  arrives while the user is parked on another day (timeline parity):
  the scroll controller now keys by the full programme-set identity
  (programsFocusKey) and commits today before focusing, instead of
  silently stranding the new channel on the stale day. (Codex P2)
- Centralise the 'timeline' fallback as a resolvedEpgViewMode computed
  on SettingsStore; the four live hosts consume the derived signal
  instead of duplicating the `?? 'timeline'` expression. (Greptile P2)
- Extract the component's reactive plumbing into
  registerEpgListViewEffects(), bringing the component back under the
  300-line guideline (290). (Greptile P2)
- Controller spec rewritten around programme-set fixtures with new
  coverage: return-to-today on channel switch, day navigation left
  alone, no-takeover when today has no data, empty-set no-op.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(epg): drop malformed programmes from the list-view day filter

Reject programmes whose stop is not after their start in
buildEpgListRows — same as the timeline's buildTimelineBlocks. Bad
provider data would otherwise render impossible time ranges and could
even be offered as catch-up playable. (Codex P2 on e6fd0d08)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 10:05:08 +02:00
4gray 401012eac4 feat(epg): rework live EPG panel into a horizontal timeline (#1102)
Replaces the vertical EPG list with a shared horizontal `app-epg-timeline`
ribbon across all live surfaces (M3U player, unified live tab, Xtream, Stalker):
zoom, day navigation, short-programme grouping, catch-up/timeshift, and
per-state empty views. Backend gains timezone-aware `datetime()` comparisons,
unscoped source fallback, non-ASCII candidate matching, and chunked candidate
queries.

Timeline split into reusable, view-agnostic modules (archive/summary/dialog
service/render util/scroll controller) for the future EPG list view.

Fixes landed during review:
- honor the controlled `selectedDate` input (seed via linkedSignal)
- restore ribbon position across collapse/expand
- keep the ribbon mounted when scrolling across a gap day
- don't trigger block playback on Enter from nested watch/info buttons
- don't reset timeshift playback on the 30s now-tick during EPG gaps

Greptile 5/5 (safe to merge); Codex clean; CI green.
2026-07-01 21:09:49 +02:00
4gray 3cb228d931 fix(m3u): highlight active archive epg program (#1097)
fix(m3u): highlight active archive epg program

* Store the active archive EPG program with the resolved playback URL so the clicked M3U catch-up row stays highlighted during archive playback.
* Show archive playback state and return-to-live controls in the inline player panel.
* Hide duplicate EPG program rows that share the same time slot while keeping the richer provider entry.
2026-06-28 14:34:51 +02:00
4gray a84090026b fix(epg): avoid duplicate track keys for archive rows (#1096)
* fix(epg): avoid duplicate track keys for archive rows

* refactor(epg): extract epg list helpers
2026-06-28 12:37:42 +02:00
4gray d43bc83531 feat(epg): improve catchup row playback handling 2026-06-27 12:02:00 +02:00
4grayand4gray e8aa7c3a34 [codex] Add scoped EPG security trust controls (#1054)
* Add scoped EPG security trust controls

* fix: address scoped trust review feedback

---------

Co-authored-by: 4gray <fourgray@proton.me>
2026-06-12 20:46:24 +02:00
Salem 2c032cd3c8 fix(security): complete Electron hardening and review follow-ups
* fix(security): harden Electron IPC against MITM, SSRF, path and injection risks

S1 TLS: validate certs by default on playlist/EPG fetches (opt-out via IPTVNATOR_ALLOW_INSECURE_TLS); new util/secure-https.ts.
S2: write-file IPC restricted to save-dialog-authorized paths.
S3: XTREAM_PROBE_URL guarded by assertRemoteUrlAllowed + maxRedirects:0; new events/url-safety.ts (+19 tests).
S4: EPG titles rendered via interpolation, not [innerHTML].
S5: downloads reveal/play limited to recorded download paths.
S6: Stalker cmd encoded (slash-preserving) to block query injection.
EPG-worker and Stalker fetches reject file://-style/credentialed URLs; LAN/self-hosted targets remain allowed.

* perf(player): lazy-load web video players via @defer

Wrap Video.js/HTML5/ArtPlayer in @defer (on immediate) so video.js, hls.js,
artplayer and mpegts.js split into a deferred chunk loaded on first playback
instead of eagerly on the player route. Embedded MPV (native) stays eager.
Spec uses DeferBlockBehavior.Playthrough.

* fix(player): remove leaked HTML video listeners on destroy

volumechange used a mismatched removeEventListener reference, while
loadedmetadata and timeupdate were never removed at all. Bind all three to
stable handler fields used for both add and remove, and add a teardown
regression test asserting each listener is detached on destroy.

* refactor(dashboard): extract pure navigation helpers from DashboardDataService

Move the 8 stateless link/navigation-state/type-kind helpers into a new
dashboard-navigation.util.ts so the routing logic is independently testable and
the 1260-line god-service shrinks. DashboardDataService keeps the public methods
as thin delegators (facade) so the public API and the single consumer
(workspace-dashboard-rails) are unchanged. First slice of the DashboardDataService
decomposition; verified by the existing service spec (33/33) and the app typecheck.

* fix(review): address PR feedback (IPv6 link-local, write-path cap, @defer placeholder)

- url-safety: broaden IPv6 link-local detection to the full fe80::/10 range
  (fe80:: through febf::), not just the fe80:: prefix (+ regression tests).
- playlist.events: cap authorizedWritePaths (evict oldest past 32) so a save
  dialog opened without a following write cannot accumulate entries until restart.
- web-player-view: add a @placeholder to each @defer (on immediate) player block
  to avoid the one-frame blank/layout-shift before the chunk resolves.

* fix(security): close Electron network and download gaps

* test(downloads): cover cancellation and restart cleanup

* fix(downloads): address Greptile review gaps

* test(security): reproduce remaining Greptile findings

* fix(security): close remaining Greptile findings

* test(downloads): reproduce early database queue stall

* fix(downloads): release queue after setup failures

* test(downloads): reproduce completion queue stall

* fix(downloads): release queue after completion failures
2026-06-12 15:24:29 +02:00
4gray 1badb9a057 refactor(electron): share typed preload bridge contract (#1018)
* refactor(electron): share typed preload bridge contract

* refactor(electron): tighten bridge review fixes

* refactor(electron): tighten playlist bridge returns

* refactor(electron): use bridge epg progress type

* refactor(epg): alias progress bridge types
2026-06-01 09:52:22 +02:00
4gray 3d4d2ca9bf fix(angular): remove template diagnostics warnings (#1011)
* fix(angular): remove template diagnostics warnings

* fix(angular): preserve template fallback behavior
2026-05-26 18:33:44 +02:00
4gray 697eab6e73 refactor(epg): route renderer calls through runtime bridge
Add typed EPG runtime bridge, split EPG runtime capabilities, migrate renderer EPG callers away from direct window.electron access, and address Greptile review feedback.
2026-05-24 13:45:51 +03:00
4gray ed8680116c fix(runtime): address consolidated review feedback 2026-05-22 14:02:56 +03:00
4gray 54d29f2239 refactor(epg): gate multi epg queries by runtime capability 2026-05-22 13:33:31 +03:00
4gray 030c6ef89d refactor(epg): gate source freshness by runtime capability 2026-05-22 13:33:31 +03:00
4gray 2ecb5c28f4 fix(dashboard): address PR review feedback 2026-05-22 00:59:17 +03:00
4grayandClaude Opus 4.7 6891a1ca30 i18n(epg): translate multi-EPG toolbar tooltips
The Zoom/Filter/Search Programs buttons in the Multi-EPG header
hard-coded English matTooltip strings, so they never localized — even
when the rest of the toolbar (Close, Previous/Next day) used keys. Adds
six new EPG.* keys (ZOOM_IN, ZOOM_OUT, FILTER_CHANNELS, CLOSE_FILTER,
SEARCH_PROGRAMS, CLOSE_PROGRAM_SEARCH), wires both [matTooltip] and
[attr.aria-label] through `| translate`, and fans the strings out to
all 17 non-English locales via the i18n-fill pipeline.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 09:15:35 +02:00
4grayandClaude Opus 4.7 7399fbfa9e refactor(multi-epg): match app theme, widen channels, label the now-line
Four UX-audit fixes for the Multi-channel EPG view:

1. Theme harmonization
   - $bg-deep / $bg-surface / $bg-elevated / $bg-hover now resolve through
     --app-content-bg / --app-widget-bg / --app-widget-header-bg /
     --app-card-hover-bg. Multi-EPG was the only screen that switched to
     near-black (#0a0a0f) instead of sitting on the app's dark surface, so
     the audit described it as "visually detaching from the rest of the
     app". It now inherits the same dark graphite chain.
   - Cleaned up 29 remaining hard-coded rgba(139,92,246,…) purples and
     rgba(0,212,170,…) teal accents that survived the earlier color
     unification commit. Purple shadows/glows are gone; the cyan glow
     used by the now-line is now driven by the unified $5cd6ff token.

2. Channel column widened 140px → 180px
   - Long names like "13th Street Universal HD" no longer truncate to 5
     characters. Logo size dropped to 24px so the name actually has room.
     The label allows up to two lines and wraps cleanly on long titles.
   - Responsive breakpoint mirrors the change: 100px → 140px at <768px.

3. Now-line time badge
   - New `currentTimeLabel` computed signal renders an "HH:MM" pill
     pinned to the top of the now-line. Recomputes on the same 60s tick
     as the line position so they always stay in lockstep.

4. "Airing now" program highlight
   - New `isProgramAiringNow(program)` returns true when the now-line's
     x-coordinate falls inside [startPosition, startPosition + width].
     Programs that match get a .is-now class → 1.5px cyan border. Users
     can now see what's on every channel at a glance without tracing the
     line down each row.

Toolbar harmonization (audit item 3 for this screen) intentionally
deferred — that's part of the app-wide toolbar unification work.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 01:21:10 +02:00
4grayandClaude Opus 4.7 a27a29fcf2 refactor(ui): unify primary color to blue across all surfaces
Swap M3 primary palette from violet to azure so checkboxes, radio
buttons, raised CTAs, and active states read as the same blue used by
the rail selection token. Cascading template + SCSS updates align the
remaining hand-rolled surfaces (Add Playlist dialog, VOD play button,
radio player, multi-EPG, empty-state CTAs) with the unified system.

LIVE stays red (broadcast role), cyan stays on EPG "now" indicator,
green stays on completed-download — semantic colors keep their meaning;
only the indiscriminate accent uses get folded into the blue primary.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 00:12:34 +02:00
4gray d24c77a143 chore(nx): enforce scoped workspace boundaries (#942) 2026-05-15 09:59:06 +02:00
4grayandClaude Opus 4.7 21fe51e73b fix(ui): redesign EPG no-data empty state to match app pattern
Replace the dashed-bordered "Ooops" placeholder in the EPG side panel
(rendered when the selected date has no programmes) with the icon +
title + hint pattern already used by groups view, season container,
and portal empty states.

The dashed border was a visual outlier — every other empty state in
the codebase is borderless, and a dashed stroke conventionally signals
a drop-zone or "add new" affordance, neither of which applies to a
passive informational state. The new layout uses a 48px event_busy
icon at 0.5 opacity, a 1.05rem title, and a 0.85rem hint at 0.65
opacity, centered in the panel via flex.

Soften the EN microcopy ("Ooops, EPG is not available for the selected
date" -> "No program guide", which also fixes the "Ooops" typo) and
add a NO_GUIDE_HINT key with localized strings across all 18 locales,
nudging the user toward the date arrows or playlist refresh.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 4bfb62f988b7
2026-05-01 22:55:17 +02:00
4grayandClaude Opus 4.7 0d79466c84 perf(ui): enable OnPush on portal channels list, fix EPG track keys
PortalChannelsListComponent renders a virtual-scrolled channel list (Xtream
live/VOD/series, can be 1000+ items). It was using default change detection,
so every CD cycle in the parent tree (EPG ticks, progress updates) re-checked
every binding. Switch to OnPush — the existing cdr.detectChanges() calls
already cover the async update paths, and signal-based state marks for check
automatically.

Replace track $index with track program.start in two EPG @for loops
(epg-list, multi-epg-container search results). $index causes Angular to
re-create DOM nodes whenever the list reorders (e.g. on EPG refresh or
timezone correction). program.start is the ISO datetime — unique per
program within a channel and stable.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 3d6901072049
2026-05-01 21:18:22 +02:00
4grayandClaude Opus 4.7 59beb324b4 refactor(styles): extract .app-scrollbar utility, apply to channel lists
Move the always-visible themed scrollbar from epg-list into a global
.app-scrollbar utility class in styles.scss. Apply it to the All
channels and Groups view virtual-scroll viewports so the channel list
gets the same persistent gutter and themed thumb as the EPG list.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: c470abf78379
2026-04-29 01:00:42 +02:00
4grayandClaude Opus 4.7 465fdbfb80 fix(epg): always-visible scrollbar in program list
Switch to overflow-y: scroll with scrollbar-gutter: stable so the gutter
is reserved (no layout shift between scrollable and non-scrollable
days). Locally style the thumb with --app-muted-color so it's clearly
visible across themes and platforms, overriding the global 6px
near-transparent style which was being hidden by the macOS overlay
auto-fade.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 918ee7ade2f3
2026-04-29 00:55:48 +02:00
4grayandClaude Opus 4.7 7841b3b4e8 refactor(epg): hairline dividers, en-dash time, single-line description
Separation: replace 4px gap with hairline dividers via ::before, hidden
around the active and current-program rows so they read as a continuous
emphasized block. Title line-height 1.4 → 1.3 + letter-spacing -0.01em
to match channel-name. Time uses en-dash, 0.78rem (parity with summary
bar), token-driven --app-muted-color. Description clamped to one line —
full text remains one click away via the info icon.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: b0389ce441a1
2026-04-29 00:52:29 +02:00
4grayandClaude Opus 4.7 db0e2b658f refactor(epg): align program-item styling with channel-list aesthetic
Drop the gradient + bevel + drop-shadow chrome from EPG rows so the panel
speaks the same flat-by-default visual language as the channel list. Add
--app-live-color token, tokenise the LIVE badge, tighten typography
(weight 600, text-wrap balance/pretty), and bump the info icon to 32px
for Fitts-compliant hit area.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 4cc5371f549e
2026-04-29 00:43:45 +02:00
4gray 31258624b5 feat: unify live epg toolbar
Entire-Checkpoint: 978eaff2e478
2026-04-29 00:20:34 +02:00
4gray 7b46509d21 feat: implement EPG source status component and enhance EPG data management in settings
Entire-Checkpoint: c6e522b4276c
2026-04-20 01:09:33 +02:00
4gray af8bb19d6c fix(epg): add retry functionality for failed EPG fetches and enhance UI for error handling
Entire-Checkpoint: c6e522b4276c
2026-04-17 21:30:50 +02:00
4gray c97673b928 refactor: refactor date handling across components to use date-fns and Intl.DateTimeFormat
- Replaced moment.js usage with Intl.DateTimeFormat for date formatting in various components.
- Introduced utility functions `normalizeDateLocale` and `formatWithIntl` for locale normalization and date formatting.
- Updated PlaylistSwitcher, RecentPlaylists, ContentCard, EPG components, and MultiEpgContainer to utilize the new date formatting approach.
- Removed moment-date pipe and related tests, simplifying date handling logic.
- Ensured all date displays respect the current locale settings.

Entire-Checkpoint: 271bd0162027
2026-04-11 10:41:33 +02:00
4gray 4005687f18 refactor: improve archive playback support and enhance EPG item display 2026-04-10 07:53:48 +02:00
4gray 826d8d24b1 feat: enhance EPG list component with program activation and scrolling improvements 2026-04-05 19:04:09 +02:00
4gray d76287e63d feat(epg): implement timeout for channel program retrieval and refactor EPG list component with signals 2026-03-28 15:42:08 +01:00
4gray b1a873edaa feat: update EPG item description layout and increase dialog width for better visibility
Entire-Checkpoint: 56d3e3141f61
2026-03-26 19:26:01 +01:00
4gray 34c2323216 feat: enhance EPG progress panel with minimized view and loading count display
Entire-Checkpoint: 1410dcc0c9ff
2026-03-26 16:01:58 +01:00
4gray 879f018a81 style: enhance theme and layout styles, improve accessibility labels, and refine component shadows
Entire-Checkpoint: 73c4b0ef53fd
2026-03-25 21:01:06 +01:00
4gray 0c451b0dd7 refactor: refactor video player component and enhance workspace header shortcuts 2026-03-16 22:55:01 +01:00
4gray 7ac2fd66b8 refactor: update nx monorepo structure 2026-03-09 23:24:34 +01:00