Commit Graph
83 Commits
Author SHA1 Message Date
4grayandClaude Opus 4.7 fe849b2de2 refactor(dashboard): live rail now favorites-first; drop mixed Favorites rail
Two related dashboard fixes driven by the v0.22 mockup intent and the
UX-audit feedback that the rail labels lied about their data:

1. Live rail is favorites-first
   - Source: globalFavoriteLiveItems() — the channels the user actually
     starred. Falls back to globalRecentLiveItems() when no favorites
     exist so fresh-install users still see something useful.
   - Title flips with the source: "Live now on your favorites" when
     pulling from favorites, "Continue with live TV" when pulling from
     recent-watch history. The label is always honest about the data.
   - "See all" link routes to the right collection page for the source
     (/workspace/global-favorites vs /workspace/global-recent).

2. Mixed Global Favorites rail removed from the dashboard
   - The rail had movies, series, live channels, and radio all sharing
     one row — different card formats fighting for visual attention.
     UX wiki principle: similar elements should look alike within a
     scanning unit.
   - Live favorites are promoted into the live rail above (with current
     EPG). The full mixed catalogue is still one click away at
     /workspace/global-favorites where the collection page can give it
     proper per-type filters.
   - Net dashboard density goes from 5 rails to 4 — closer to the
     streaming-app sweet spot.

i18n: new WORKSPACE.DASHBOARD.LIVE_CONTINUE key, translated across all
17 locales by per-locale agents (placeholder integrity verified).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 01:01:22 +02:00
4grayandClaude Opus 4.7 9bb41f59b0 feat(dashboard): show watch progress on hero and Continue Watching cards
Wire the playback-position store into DashboardDataService so the hero
and Continue Watching cards can show how far through each title the user
is. Per-playlist bulk fetch via getAllPlaybackPositions (one IPC call
each, no N+1) cached in an in-memory Map keyed by playlist + content id
+ content type — supports both VOD and episode keys, since the same
xtream-id can map to either.

Hero:
- Thin 4px progress bar under the subtitle when a position is known
- "1h 04m left · 38% watched" meta line below it (formatRemainingLabel
  handles sub-minute, minute, hour, and hour+minute remainders)
- Tighter padding (16 vs 20) and smaller poster (140 vs 160) per the
  v0.22 mockup spec — frees ~30px of vertical space without losing
  legibility

Continue Watching cards:
- 3px progress overlay pinned to the bottom of the poster art, painted
  in the unified blue primary (--app-selection-color)
- Renders only when watchProgress is set, so live channels and untracked
  M3U items remain unaffected

Live channels and M3U items never have positions in the schema, so the
new UI is purely additive — both surfaces degrade gracefully to the
prior layout when the lookup misses.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 00:50:11 +02:00
4grayandClaude Opus 4.7 bb6d1427fa feat(dashboard): compact channel cards with lazy-loaded current EPG
The "Live now on your favorites" rail no longer reuses the 2:3 poster
card built for movies. TV station logos are typically 100–256px square,
so inflating them into portrait cards wastes most of the height and
hides the data users actually care about (what's airing right now).

Introduce a `layout: 'cover' | 'channel'` input on DashboardRailComponent.
The new channel layout is a wider, much shorter card: logo + channel
name + current program title + LIVE chip + progress bar + time range.

Current programs are lazy-loaded via EpgService.getCurrentProgramsForChannels
(already batched + 60s-cached at the service), keyed by the recent item's
display name — works out of the box for M3U sources whose XMLTV channels
resolve through the tvg-id → tvg-name → name fallback chain. A 30s tick
keeps the progress bar fresh between program boundaries.

The card renders gracefully without EPG enrichment (idle progress bar,
no program title) so Xtream/Stalker live items without an XMLTV side
channel still look fine.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 00:34:43 +02:00
4grayandClaude Opus 4.7 a048c18763 refactor(dashboard): split recently-watched into VOD and live rails
Per UX audit: a single "Recently Watched" rail mixed channels and VOD
into a grid where the two card formats fought for visual attention.
Split it into two rails — "Continue watching" (movies/series) and
"Live now on your favorites" (live channels) — so each surface uses
the card format that fits its content type.

Also relabel the rail header link from "Manage all" to "See all {N}"
when the total count exceeds what's rendered, so the user knows how
many items the link expands into; falls back to "See all" otherwise.

i18n: three new keys (LIVE_RECENT, SEE_ALL, SEE_ALL_COUNT) translated
across all 17 locales by per-locale agents reusing each file's existing
glossary; placeholder integrity verified.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 00:18:46 +02:00
4gray 2d5c4fa4f9 chore: tighten validation and runtime logging
* chore: tighten validation and runtime logging

* fix(i18n): localize new settings labels
2026-05-15 17:43:42 +02:00
4gray d24c77a143 chore(nx): enforce scoped workspace boundaries (#942) 2026-05-15 09:59:06 +02:00
4gray 8232a86a1e feat(portal): add category sorting controls (#940)
* feat(portal): add category sort modes

* fix(portal): address category sort review feedback
2026-05-15 00:28:32 +02:00
4gray 2a5b1d1da7 fix(xtream): keep live playback on category switch (#936) 2026-05-14 20:52:02 +02:00
4gray aead89e3e6 fix(xtream): keep category management available
Fixes #913
2026-05-09 18:34:57 +02:00
4gray ab905af285 feat(stalker): add radio support
Entire-Checkpoint: f957cd9849e0
2026-05-09 01:28:39 +02:00
Eliran Sapir a3a4c6b5ea Fix Xtream section search across categories 2026-05-07 17:42:29 -04:00
4gray 2efdfea0c1 fix: preserve file paths for local playlist refresh
Refs https://github.com/4gray/iptvnator/issues/891

Entire-Checkpoint: f957cd9849e0
2026-05-04 10:06:39 +02:00
4gray d0f590d8fe refactor: improve Xtream refresh functionality with localization support
- Introduced new localization keys for Xtream refresh actions in multiple languages (ar, ary, by, de, el, en, es, fr, it, ja, ko, nl, pl, pt, ru, tr, zh, zhtw).
- Implemented refresh preparation state management in PlaylistRefreshActionService.
- Enhanced WorkspaceShellXtreamImportService to handle refresh preparation states and display appropriate labels.
- Updated tests to cover new refresh preparation scenarios and ensure correct overlay display during refresh operations.

Entire-Checkpoint: f957cd9849e0
2026-05-04 00:51:29 +02:00
4gray e36c953865 feat(sidebar): implement shared collapse state for live-TV sidebar across components
Entire-Checkpoint: f957cd9849e0
2026-05-03 23:26:52 +02:00
4grayandClaude Opus 4.7 cf30c129f1 perf(ui): lazy-load content-card images + OnPush on sources filters panel
Two small focused changes from an Angular perf audit.

content-card lazy loading
ContentCard is the building block for catalog grids and rails — Xtream
recently-added (3 rails × 20 = 60 cards on first paint), Xtream/Stalker
search results, unified favorites/recent grids. The poster <img> had
no loading attribute, so every off-screen card eagerly fetched its
poster from the Xtream/Stalker server on initial render. Same fix
already in place on the dashboard rail's separate <img>; mirror it on
the shared ContentCard so every consumer benefits.

Add loading="lazy" decoding="async" to both <img> tags (real poster
and the default-poster fallback). Browser defers off-screen requests;
no JS changes.

OnPush on workspace-sources-filters-panel
The sources filters panel renders one row per filter option and
displays {{ getTypeCount(option.id) }} per row — that method is a
plain Map lookup but fires every CD cycle under default change
detection. The component is signal-only (computed + selectSignal, no
subscribes) so the OnPush conversion is purely additive.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: f957cd9849e0
2026-05-02 17:58:59 +02:00
4grayandClaude Opus 4.7 13acbe7e3d perf(dashboard): memoize M3U favorite parses + stream per-playlist updates
Two compounding wins for the dashboard's M3U favorites path.

#3 — Memoize loadM3uPlaylistFavorites
The function calls getPlaylistById() which deserializes the entire
M3U playlist payload (potentially 90K channels) just to read the
favorites field and the matching items. On every dashboard mount, it
re-paid that cost for every M3U playlist with favorites — even though
nothing relevant had changed.

Add a per-playlist cache keyed by playlist ID with a fingerprint of
{updateDate, favorites JSON}. A cache hit skips the heavyweight
playlist read entirely; a refresh (updateDate change) or favorites
add/remove naturally invalidates without explicit busting. First
mount still pays the parse; subsequent dashboard visits and
re-renders are effectively free.

#4 — Stream per-playlist favorites into the rail
reloadM3uGlobalFavorites used Promise.all over loadM3uPlaylistFavorites
and wrote one flat array at the end, so a single slow M3U playlist
pinned the entire M3U favorites contribution behind it.

Replace the writable m3uGlobalFavorites signal-of-array with a
WritableSignal<Map<playlistId, items[]>> + computed flatten. Each
playlist's contribution lands in the map as soon as ITS load resolves
(usually instant via the new cache), so the favorites rail re-renders
incrementally — Xtream favorites first, then each M3U playlist's
favorites appear as it streams in.

Cache + map entries for playlists that no longer have favorites are
pruned at the start of each reload, so removed playlists don't leave
stale state.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: fb28be89e785
2026-05-02 09:18:08 +02:00
4grayandClaude Opus 4.7 d67150d38f perf(dashboard): per-rail skeletons + drop CAST that blocked content index
Two independent fixes that compound: the dashboard now renders progressively
as each rail's data resolves, and the slowest of those rails (Xtream
recently-added) no longer scans the entire content table.

Per-rail skeletons (template restructure):
The old @if (!ready()) gate hid the whole dashboard until ALL FOUR loading
flags resolved (playlistsLoaded, globalRecentLoaded, globalFavoritesLoaded,
xtreamRecentlyAddedLoaded). The slowest one pinned the entire skeleton up
for the full tail latency — visibly seconds of "loading" even when 3 of 4
rails could have rendered immediately.

Replace with per-rail conditionals:
- Hero: renders the moment globalRecentItems[0] is available; skeleton
  shows only while data.globalRecentLoading() is true and no item exists.
- Each rail: shows real content if its cards are non-empty, its own
  skeleton if its dedicated loading flag is true, nothing otherwise.
- The Xtream recently-added rail's skeleton is gated on having Xtream
  playlists at all, so M3U-only users never see a skeleton for it.

The loading signals were already exposed on DashboardDataService
(globalRecentLoading, globalFavoritesLoading, xtreamRecentlyAddedLoading)
but went unused because of the monolithic gate. Same skeleton markup is
reused per rail; no styling changes.

Drop CAST(added AS INTEGER) in getGlobalRecentlyAdded:
The query ordered by sql<number>\`CAST(content.added AS INTEGER)\`. SQLite
cannot use an index on a column wrapped in a function, so the existing
idx_content_type_added index was bypassed and the planner did a full table
scan + sort on content (10k–100k+ rows for a typical Xtream catalog) on
every dashboard load.

Sort by schema.content.added directly. Xtream stores Unix-epoch timestamps
as 10-digit numeric strings (anything since 2001-09-09), so lexicographic
and numeric sort are equivalent. The (type, added) index now drives the
ORDER BY too — full table scan becomes an index range scan + LIMIT 20.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 1e3392724bc8
2026-05-02 09:09:10 +02:00
4grayandClaude Opus 4.7 d1e4c0d306 fix(portal): show search-aware empty state when category search yields no results
When a search filter inside a category produces zero results, the grid
@empty fallback used to render the EMPTY_CATEGORY view ("No content in
this category" with the empty-tv illustration). That message was
misleading — the category itself wasn't empty, only the search filter
excluded everything.

grid-list now takes a searchTerm input and branches the @empty fallback:
when a search is active it renders the NO_SEARCH_RESULTS view with the
parameterised "No results found for {term}" title, otherwise it falls
back to EMPTY_CATEGORY as before. category-content-view derives the
searchTerm signal from the ?q= query param and passes it through.

Also: bump the NO_SEARCH_RESULTS icon from a 64px mat-icon to a clamp()
sized icon (120-180px) at 0.5 opacity so it visually balances with the
SVG illustrations used by the other viewTypes, swap the icon to
search_off (struck-through magnifier) so it reads as "no results"
rather than "search now", and fix the EN i18n typo
("change you search request" -> "change your search request").

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 2e1a36e2f0f6
2026-05-01 23:17:22 +02:00
4gray 1af287205f perf: optimize playlist favorite lookups
Use Map and Set lookups for M3U favorite aggregation, dashboard global favorite mapping, and channel-list favorite/group resolution.

Remove the duplicate NgxIndexedDB provider registration and add regression coverage for duplicate URL and earliest-match behavior.

Entire-Checkpoint: c2cea9c530e6
2026-05-01 20:44:30 +02:00
4gray 6ef9e8c4b0 fix(web): lazy load route feature boundaries
Entire-Checkpoint: c2cea9c530e6
2026-05-01 20:38:14 +02:00
4grayandClaude Opus 4.7 d24c67c6e8 test(workspace-shell): repair stale component-spec mocks and cover new overlay child
The two component specs in this lib had been carrying 7 long-standing
failures rooted in three stale-mock issues, all unrelated to public
behaviour but enough to make the suite red on every run.

Header spec (5 failures, NG0303 on app-playlist-switcher):
- MockPlaylistSwitcherComponent was missing canRefreshActivePlaylist /
  isRefreshingActivePlaylist inputs and refreshPlaylistRequested
  output. The real PlaylistSwitcherComponent grew them when refresh
  was added to the header; the mock never caught up. Re-aligned.

Workspace-shell component spec (2 failures):
- NG0301 on #dropZone="playlistDropZone" because overrideComponent's
  set.imports list dropped PlaylistDropZoneDirective and the drop
  overlay component. Added MockPlaylistDropZoneDirective and
  MockPlaylistDropOverlayComponent.
- After the recent option-D refactor that lifted the import overlay
  into its own child component, the spec also needed
  MockWorkspaceShellImportOverlayComponent so the parent template
  could resolve <app-workspace-shell-import-overlay />.
- MockWorkspaceShellHeaderComponent gained hasNoPlaylists input and
  MockWorkspaceShellContextSidebarComponent gained hasPlaylists input
  to match the real components.
- The "renders type-aware xtream import progress copy" test asserted
  on inline overlay markup that no longer lives in the parent
  template. Replaced with a structural test that the overlay child
  renders/unmounts based on facade.showXtreamImportOverlay().

New focused spec for WorkspaceShellImportOverlayComponent (6 tests)
covers the moved progress-copy assertion at the right level by mocking
the WorkspaceShellXtreamImportService directly: title, progress copy,
determinate vs indeterminate progress bar, badge tone, and cancel
forwarding.

Final state: full feature lib suite is 66/66 (was 53/60 with 7
chronic failures). pnpm nx test web, pnpm nx lint
workspace-shell-feature, pnpm nx build web --configuration=production,
and the basic + settings web-e2e suites all pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: c2cea9c530e6
2026-05-01 19:34:45 +02:00
4grayandClaude Opus 4.7 63f5173139 refactor(workspace-shell): push xtream import overlay and bulk action into child components
Continues the workspace-shell facade decomposition by relocating two
clusters from the parent template into the components that own them.

Xtream import overlay:
- New WorkspaceShellImportOverlayComponent injects
  WorkspaceShellXtreamImportService directly. The 70-line inline
  overlay block in workspace-shell.component.html collapses to a
  single <app-workspace-shell-import-overlay /> element, gated by
  facade.showXtreamImportOverlay().
- Overlay-specific styles move from workspace-shell.component.scss
  into the child component (~125 lines relocated).
- Facade drops 14 import re-export lines plus the cancelXtreamImport
  delegation. The two facade tests that exercised label generation
  now resolve the service via TestBed.inject and assert against it
  directly.

Header bulk action:
- WorkspaceShellHeaderComponent gains headerBulkAction input and
  headerBulkActionRequested output, plus a button that renders the
  action when present (next to the existing headerShortcut button).
- The parent template wires facade.headerBulkAction() →
  facade.runHeaderBulkAction(). The facade keeps the cross-cutting
  computed and the multi-store dispatch method since both span
  multiple stores.

Verification:
- workspace-shell.facade.spec.ts: 20/20 passing (two assertions
  retargeted at WorkspaceShellXtreamImportService).
- Full feature lib: 53/60 passing — same 7 pre-existing failures.
- pnpm nx build web --configuration=production: success.
- pnpm nx lint workspace-shell-feature: clean.
- pnpm nx run web-e2e:e2e-ci--src/basic.e2e.ts: 3/3 across browsers.
- pnpm nx run web-e2e:e2e-ci--src/settings.e2e.ts: 12/12 across
  browsers.

Facade: 917 → 897 lines. The bulk-action button now actually renders
in the header — closing a latent gap where the computed existed on
the facade but had no template binding.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: c2cea9c530e6
2026-05-01 19:12:19 +02:00
4grayandClaude Opus 4.7 0ad54e7939 fix(workspace-shell): accept readonly viewCommands in palette builder
Production build (stricter than test/dev) flagged the helper signature
as requiring a mutable array while WorkspaceViewCommandService.commands
returns readonly. The body uses spread, so widening the parameter to
readonly is the correct fix and unblocks `nx build web` plus E2E.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: c2cea9c530e6
2026-05-01 18:59:24 +02:00
4grayandClaude Opus 4.7 d1cd805622 refactor(workspace-shell): split 1666-line facade into helpers and sub-services
The WorkspaceShellFacade had grown to 1666 lines, well past the 300/400
LOC target in CLAUDE.md. The component template binds to 54 facade
members directly, so the split preserves the public API by reference
re-export and keeps the template untouched.

Phase 1 — extract pure helpers (no DI, no behavior change):
  - helpers/workspace-shell-constants.ts: i18n keys, RAIL_TOOLTIP_KEYS,
    XtreamImportPhaseTone, WorkspaceHeaderBulkAction
  - helpers/workspace-shell-route-utils.ts: toQueryString,
    getRouteQueryParam, syncSearchQueryParam, bumpRefreshQueryParam,
    getProviderFromPlaylist
  - helpers/workspace-shell-search-labels.ts: resolveSearchPlaceholderKey,
    resolveSearchScopeLabel, resolveActiveCategoryLabel, getRailTooltipKey,
    translateRailLinks (each takes TranslateFn + snapshots as params)
  - helpers/workspace-shell-import-labels.ts: build* helpers for the 14
    Xtream import overlay labels and formatLocalizedNumber
  - helpers/workspace-shell-command-builders.ts: buildCommandPaletteItems
    plus the three command-definition builders, navigation command
    factory, resolveCommand, comparePaletteCommands, getCommandGroupOrder

Phase 2 — extract the two component-scoped sub-services with the
cleanest boundaries:
  - WorkspaceShellXtreamImportService: read-only labels, cancel action,
    isImportRunning. Reads only XtreamStore + TranslateService.
  - WorkspaceShellCommandPaletteService: MatDialog lifecycle, recent
    commands integration, eager WorkspacePlayerCommandsContributor
    bootstrap. Receives a typed CommandBuilderContext via function
    argument from the parent — no circular DI.

The parent facade re-exposes every member by reference assignment so
signal identity is preserved for change detection. workspace-shell.
component.html is unchanged. workspace-shell.component.ts gains only
two provider entries for the new sub-services.

Verification:
  - workspace-shell.facade.spec.ts: 20/20 passing
  - pnpm nx lint workspace-shell-feature: clean
  - workspace-shell-feature suite: 53/60 passing — same 7 pre-existing
    failures (header & shell component specs hit unrelated NG0301
    on playlistDropZone export); no regressions introduced
  - CDP smoke: command palette opens with Recently Used + Global
    Actions groups, settings nav disables search bar correctly

Facade reduces from 1666 to 917 lines. Each new helper/service is
under 250 lines except command-builders.ts (462) which is mostly
declarative command definitions. The parent facade is still over the
400-line hard max because cross-cutting orchestration
(searchCapability, runHeaderBulkAction, rail link computeds) reads
from multiple clusters; further reduction would require moving logic
into child components, which is deferred per the plan.

Plan: ~/.claude/plans/workspace-shell-facade-ts-is-now-1668-crispy-planet.md
(also copied locally to .plans/2026-05-01-workspace-shell-facade-split.md;
the working-tree .gitignore change excludes .plans from tracking).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: c2cea9c530e6
2026-05-01 18:48:53 +02:00
4grayandClaude Opus 4.7 2f47ed16cb feat(command-palette): add recently used section and switch-player commands
Adds a "Recently used" section at the top of the command palette (capped at 5,
persisted via StorageMap) and five "Switch player to ..." commands for one-step
player switching from anywhere. MPV/VLC are gated to Electron; the active player
entry is shown disabled. Switching applies to the next playback session.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: c2cea9c530e6
2026-04-30 23:54:02 +02:00
4gray b5a85fdf5f style: add shared count-badge style and update component usage
Entire-Checkpoint: c2cea9c530e6
2026-04-30 20:32:55 +02:00
4gray 4b2076fa53 feat(settings): add cover size settings and implement responsive cover sizing
Entire-Checkpoint: c2cea9c530e6
2026-04-30 18:56:06 +02:00
4gray cbedb22698 refactor: enhance live stream layout with loading state and caching
- Added `XtreamCachedContentScope` type to manage content loading states.
- Updated live stream layout to show a loading skeleton when content is being fetched.
- Introduced styles for loading content in the live stream layout.
- Enhanced unit tests to cover loading states and caching behavior.
- Modified `XtreamWorkspaceRouteSession` to handle cached content loading and state management.
- Improved handling of optional connection values in playlist data.
- Updated workspace context panel to reflect import states and loading conditions.

Entire-Checkpoint: c2cea9c530e6
2026-04-30 18:54:58 +02:00
4grayandClaude Opus 4.7 2db99769f9 fix(scrollbar): make .app-scrollbar override component-scoped overflow
Two issues kept the scrollbar invisible on the global Favorites and
Recently viewed live-tv lists:

1. The wrong files. The visible Favorites/Recent pages render through
   <app-global-favorites-list> from portal/shared/ui (and the
   workspace-shell variant), not the channel-list-container's tabs.
   Apply .app-scrollbar to both of those components.

2. Specificity. Component CSS gets an Angular [_ngcontent-xxx]
   attribute selector, so `.nav-list { overflow-y: auto }` resolves to
   (0,2,0) — same as the doubled `.app-scrollbar.app-scrollbar` and
   wins on source order (component CSS loads after globals). Mark
   overflow-y: scroll !important on the utility so the contract holds:
   applying .app-scrollbar always reserves the gutter.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 8ae011808369
2026-04-29 01:13:58 +02:00
4grayandClaude Opus 4.7 d163a1fbf2 feat(dashboard): contained logo + blurred backdrop for live channels
Render live TV channel logos with object-fit: contain on a soft blurred
wash sampled from the logo itself, instead of stretching small (100-256px)
logos to fill 2:3 portrait cards with object-fit: cover. Mirrors the
treatment used by Apple Podcasts and Plex Live TV. VOD/series posters
still get the full-bleed cover treatment.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 6bb6f5796090
2026-04-28 20:14:04 +02:00
4gray 313ff7a24f fix(command-palette): enhance command palette management with dialog reference
Entire-Checkpoint: c6e522b4276c
2026-04-26 01:06:36 +02:00
4gray 4bc733d9c2 refactor(external-playback): update styles
Entire-Checkpoint: c6e522b4276c
2026-04-25 23:48:21 +02:00
4gray 92f21bd237 feat(workspace): enhance dashboard and sources components with playlist management and UI improvements
Entire-Checkpoint: c6e522b4276c
2026-04-25 22:11:31 +02:00
4gray caed2ce396 feat(playlist-drop-overlay): add component and directive for file drop overlay functionality
Entire-Checkpoint: c6e522b4276c
2026-04-25 22:08:03 +02:00
4gray a76f09a8ce style(dashboard): enhance hero artwork handling with fallback logic and image failure management
Entire-Checkpoint: c6e522b4276c
2026-04-25 15:11:25 +02:00
4gray efa0385fc8 feat(dashboard): implement context menu with actions for recent sources 2026-04-24 14:27:04 +02:00
4gray 0e77f7b98a refactor: rework dashboard view
- Removed global favorites related properties and methods from WorkspaceShellHeaderComponent.
- Updated WorkspaceShellFacade to streamline command palette commands and navigation.
- Refactored command palette to include type-aware xtream import progress labels.
- Enhanced WorkspaceShellComponent to display import progress with improved styling.
- Updated tests to reflect changes in command palette and import progress handling.
2026-04-22 22:19:42 +02:00
4gray 5e41e3d1ce refactor(favs-recent): adapt UI and routing behavior
- Introduced StalkerCollectionDetailComponent to handle detailed views for Stalker collections.
- Added XtreamCollectionDetailComponent for managing Xtream collection details.
- Updated routing components to integrate new detail components for both Stalker and Xtream.
- Enhanced global favorites and recently viewed functionalities to support new detail navigation for Stalker and Xtream items.
- Improved styling and structure for better responsiveness and user experience in detail views.

Entire-Checkpoint: c6e522b4276c
2026-04-18 10:16:09 +02:00
4gray e0f6b34aa0 style: update form field styles and dialog components
- Set default appearance for mat-form-field to 'outline' and dynamic subscript sizing in app.config.ts.
- Adjust dialog dimensions in workspace-shell-actions.service.ts for better responsiveness.
- Refactor settings.component.scss to remove specific mat-form-field font size overrides.
- Enhance global styles in m3-theme.scss for outlined inputs, ensuring consistency across the application.
- Modify workspace-command-palette styles to improve visual integration with the overall theme.
- Revamp add-playlist-dialog component to utilize segmented controls for category selection, improving UX.
- Update file-upload component to provide better feedback on file selection and drag-and-drop interactions.
- Clean up text and URL upload components by removing unnecessary placeholders and improving layout.
- Refine stalker-portal-import component by removing placeholder text for clarity.

Entire-Checkpoint: c6e522b4276c
2026-04-17 23:20:17 +02:00
4gray b1c72a7782 style: enhance workspace sources with sorting functionality and UI improvements
Entire-Checkpoint: c6e522b4276c
2026-04-14 17:04:30 +02:00
4gray 156c12c51a feat: enhance playlist switcher with dynamic type filters and add playlist functionality
Entire-Checkpoint: 50668c5f4b12
2026-04-12 19:35:41 +02:00
4gray bd76d8456d style: update playlist switcher and header styles for improved UI/UX
Entire-Checkpoint: a0a3e00085b7
2026-04-12 19:23:25 +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 77dbfd7eae style: unify search bar styling across components and improve display properties
Entire-Checkpoint: dd05e045e1b2
2026-04-11 08:13:39 +02:00
4gray 76e4e1b032 feat: enhance playlist management by adding optional title input and updating URL submission logic 2026-04-06 17:57:04 +02:00
4gray 5fdd999c7e style: enhance settings UI with responsive action bar and snackbar adjustments 2026-04-06 17:56:50 +02:00
4gray 70b7f570ef feat: enhance workspace command palette and context panel
- Added new commands to the workspace command palette including open-settings, open-sources, open-dashboard, add-playlist, refresh-playlist, playlist-info, account-info, and navigation commands for vod, live, and series.
- Updated command icons for new commands in workspace-command-palette.component.ts.
- Improved workspace context category view with inline status messages and loading indicators for item counts.
- Refactored category view to use buttons instead of links for better accessibility and interaction handling.
- Introduced search functionality in the workspace context panel to filter categories.
- Enhanced styling for the context panel and header components, including a download activity indicator.
- Added tests for the workspace context panel to ensure proper functionality and interaction handling.

Entire-Checkpoint: 271bd0162027
2026-04-04 20:22:24 +02:00
4gray 8b5344ef26 feat: enhance DashboardDataService with loading states and global favorites handling 2026-04-04 10:11:22 +02:00
4gray eaa3e0e2bd feat: add loading state and spinner to source stats widget
- Introduced a loading state in the source stats widget with a spinner.
- Updated styles for the loading state in the SCSS file.
- Created unit tests for the source stats widget to verify loading behavior.
- Enhanced the source stats widget component to include a progress spinner.
- Added a new service for managing workspace startup preferences.
- Implemented logic to determine the initial workspace path based on user settings.
- Updated workspace shell header to include a refresh playlist button.
- Refactored workspace shell rail component to support dynamic brand link and tooltip.
- Enhanced workspace shell facade to manage playlist refresh actions.
- Improved loading overlay UI in the workspace shell component.

Entire-Checkpoint: 271bd0162027
2026-04-04 10:10:52 +02:00
4gray a15ac7f7c1 test(e2e): enhance category management dialog and update playlist handling 2026-04-01 22:41:15 +02:00