-
-
Notifications
You must be signed in to change notification settings - Fork 653
feat-info-overlay-no-epg-layout #653
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat-info-overlay-no-epg-layout #653
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the Note
|
| Cohort / File(s) | Summary |
|---|---|
Backend Playlist Updates apps/electron-backend/src/app/events/playlist.events.ts |
Preserves additional user-specific data (favorites array and userAgent) when updating playlists during auto-refresh. |
EPG Service Layer libs/services/src/lib/epg.service.ts |
Introduces in-memory EPG caching with 60-second TTL; adds getCurrentProgramForChannel(), getCurrentProgramsForChannels(), and clearCache() APIs for channel-level program lookups. |
M3U State Effects libs/m3u-state/src/lib/effects.ts |
Adds guard to skip EPG/IPC operations when channel is undefined in setActiveChannel flow. |
Video Player Integration apps/web/src/app/home/video-player/video-player.component.* |
Adds keyboard shortcut (I key) and method toggleInfoOverlay() for manual info overlay triggering; wires toolbar output to overlay toggle; extends playlist initialization to load/clear favorites. |
Toolbar Controls libs/ui/components/src/lib/video-player/toolbar/toolbar.component.* |
Adds isLeftDrawerOpened input and infoOverlayClicked output; adds info button with tooltip binding. |
Channel List Container libs/ui/components/src/lib/channel-list-container/channel-list-container.component.ts |
Implements OnInit lifecycle, introduces EPG state tracking (channelEpgMap), adds 60-second EPG refresh interval, batch-fetches EPG for all channels, and rewires favorites$ via combineLatest(). |
Channel List Container Template & Styles libs/ui/components/src/lib/channel-list-container/channel-list-container.component.* |
Replaces mat-nav-list with div containers; increases virtual scroll item size from 50 to 68; adds [epgProgram] bindings to channel items; enforces overflow-x hidden on containers; adds empty-state styling for favorites. |
Channel List Item libs/ui/components/src/lib/channel-list-container/channel-list-item/channel-list-item.component.ts |
Implements OnInit, OnChanges, OnDestroy; adds showEpg input and epgProgram input; introduces progress tracking with 30-second refresh interval; adds calculateProgress() and formatTime() helpers. |
Channel List Item Styles libs/ui/components/src/lib/channel-list-container/channel-list-item/channel-list-item.component.scss |
Complete style overhaul: replaces minimal truncation with BEM-like structure including drag handle, content sections, EPG display with progress track/fill, animations, and theme variants. |
Info Overlay Component libs/ui/components/src/lib/info-overlay/info-overlay.component.ts |
Adds showOverlay() method; handles undefined epgProgram in ngOnChanges; increases auto-hide timeout to 10000ms; adds TranslatePipe import. |
Info Overlay Template & Styles libs/ui/components/src/lib/info-overlay/info-overlay.component.* |
Restructures layout to EPG-driven template with separate branches for program info (timeline, progress bar, description) and no-EPG fallback; adds progress animation, shimmer effects, and refined typography with Crimson Pro and DM Sans fonts. |
EPG List Component libs/ui/components/src/lib/epg-list/epg-list.component.ts |
Changes setPlayingNow() to always dispatch setCurrentEpgProgram action, even when playingNow is null/undefined (previously skipped dispatch). |
Localization apps/web/src/assets/i18n/en.json |
Adds TOP_MENU.SHOW_INFO ("Show program info (Press I)") and EPG.NO_PROGRAM_INFO ("No program information available") keys. |
Sequence Diagram(s)
sequenceDiagram
actor User
participant VP as VideoPlayer
participant Toolbar
participant InfoOverlay
participant EPGService
Note over User,EPGService: Info Overlay Trigger
User->>VP: Press 'I' key or<br/>click Info button
alt Keyboard Shortcut
VP->>VP: handleInfoKeyPress()
else Toolbar Button
Toolbar->>Toolbar: infoOverlayClicked.emit()
Toolbar->>VP: (infoOverlayClicked)
end
VP->>VP: toggleInfoOverlay()
VP->>InfoOverlay: Show overlay<br/>(10s auto-hide)
rect rgb(230, 245, 255)
Note over InfoOverlay: Display Program Info
InfoOverlay->>InfoOverlay: Render EPG details<br/>(title, timeline, progress)
alt EPG Available
InfoOverlay->>InfoOverlay: Show program & progress bar
else No EPG
InfoOverlay->>InfoOverlay: Show "No info available"
end
end
sequenceDiagram
participant CLC as ChannelListContainer
participant Items as ChannelListItem
participant EPGService
participant Store
Note over CLC,Store: EPG State Management & Refresh
CLC->>CLC: ngOnInit()
CLC->>CLC: Start 60s refresh interval
CLC->>CLC: fetchEpgForChannels(channels)
CLC->>EPGService: getCurrentProgramsForChannels([...])
loop For Each Channel
EPGService->>EPGService: Check cache (60s TTL)
alt Cache Hit
EPGService->>EPGService: Return cached program
else Cache Miss
EPGService->>Store: Fetch EPG from backend
Store->>EPGService: Return programs
EPGService->>EPGService: Cache result + timestamp
end
end
EPGService->>CLC: Return Map<channelId, program>
CLC->>CLC: Store in channelEpgMap
CLC->>Items: Emit programChange<br/>via binding
Items->>Items: calculateProgress() every 30s
Items->>Items: Render progress bar & timeline
Estimated code review effort
🎯 4 (Complex) | ⏱️ ~50 minutes
Areas requiring extra attention:
- Channel List Container (
channel-list-container.component.ts): Complex state management refactoring usingBehaviorSubjectandcombineLatest; verify thefavorites$composition correctly merges store favorites with channel list updates and handles undefined channels. - Channel List Item Progress Tracking (
channel-list-item.component.ts): Introduces lifecycle-managed interval-based progress updates; verify proper cleanup inngOnDestroy, change detection triggering, and interval cancellation logic. - EPG Caching Layer (
epg.service.ts): Verify TTL logic correctly handles cache expiration; edge cases when channels are fetched mid-request; proper error handling in batch operations. - Info Overlay Restructuring (
info-overlay.component.*): Significant template/style changes with new layout branches; verify EPG and non-EPG paths both render correctly and animations function smoothly. - Behavioral Change in EPG List (
epg-list.component.ts): Now always dispatches even with null programs; verify store reducers handle null/undefined programs correctly.
Possibly related PRs
- refactor/ipc-events-handling #644: Modifies playlist metadata handling to propagate userAgent across player-launch IPC flows; aligns with the userAgent preservation in playlist auto-updates.
- fix/m3u-auto-refresh-mechanism #648: Extends the playlist auto-update handler in
apps/electron-backend; this PR builds on that foundation by preserving additional fields (favorites, userAgent).
Poem
🐰 A Rabbit's Ode to Channels & Programs
Cache the programs, sixty seconds strong,
Show the info when the key goes ding-dong!
Progress bars shimmer as programs play,
Favorites refreshed throughout the day. ✨📺
Pre-merge checks and finishing touches
✅ Passed checks (3 passed)
| Check name | Status | Explanation |
|---|---|---|
| Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled. |
| Title check | ✅ Passed | The title 'feat-info-overlay-no-epg-layout' is specific and directly reflects a primary change: adding a no-EPG layout for the info overlay component. |
| Docstring Coverage | ✅ Passed | No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. |
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
Comment @coderabbitai help to get the list of available commands and usage tips.
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
libs/m3u-state/src/lib/effects.ts (1)
130-140: Guard currently risks an infinite setActiveChannel loop
setActiveChannel$listens forPlaylistActions.setActiveChanneland, in the new guard, returns the sameactionwhenchannelis falsy. Because this effect hasdispatch: true(default), that re-dispatchessetActiveChannel, which re-enters the same effect and can create an infinite loop wheneverchannelis undefined.Consider filtering out falsy channels before
map, or mapping to a different action that the effect does not listen to. For example:@@ - return this.actions$.pipe( - ofType(PlaylistActions.setActiveChannel), - map((action) => { - const { channel } = action; - - // Guard against undefined channel - if (!channel) { - return action; - } + return this.actions$.pipe( + ofType(PlaylistActions.setActiveChannel), + // Skip the effect entirely when channel is falsy + filter((action) => !!action.channel), + map((action) => { + const { channel } = action; @@ return PlaylistActions.setActiveChannelSuccess({ channel: action.channel, }); }) );Don’t forget to add
filterto the RxJS imports at the top.
🧹 Nitpick comments (9)
apps/electron-backend/src/app/events/playlist.events.ts (1)
154-161: User data preservation looks good!The preservation of
favoritesanduserAgentduring auto-refresh correctly maintains user customizations across playlist updates. Thefavoritesfallback to an empty array is a good defensive pattern.For consistency, consider applying a similar defensive approach to
userAgent:...playlistObject, _id: playlist._id, autoRefresh: playlist.autoRefresh, favorites: playlist.favorites || [], // Preserve favorites - userAgent: playlist.userAgent, // Preserve custom user agent + ...(playlist.userAgent && { userAgent: playlist.userAgent }), // Preserve custom user agentThis avoids adding
userAgent: undefinedto the object when no custom user agent is set, keeping the object shape cleaner.libs/ui/components/src/lib/epg-list/epg-list.component.ts (1)
208-227: Align setPlayingNow with null-clearing intent and avoid nested subscriptionsThe new behavior (always dispatching
setCurrentEpgProgram, even when no program matches “now”) makes sense for clearing stale EPG, but a couple of details could be improved:
- Nested subscription and potential accumulation
setPlayingNowsubscribes tothis.items$whilengOnInitalready subscribes to the same stream and callshandleEpgData, which in turn callssetPlayingNow. Over time this can build up multiple subscriptions toitems$.A simpler and safer pattern is to derive
playingNowdirectly from the array you already have inhandleEpgData:// handleEpgData if (programs.length > 0) { this.setPlayingNow(programs); } else { this.channel = {} as EpgChannel; this.store.dispatch(resetActiveEpgProgram()); }setPlayingNow(programs: EpgProgram[]): void { const nowIso = new Date().toISOString(); const playingNow = programs.find((item) => { const start = new Date(item.start).toISOString(); const stop = new Date(item.stop).toISOString(); return nowIso >= start && nowIso <= stop; }) ?? null; this.playingNow = playingNow; this.store.dispatch(setCurrentEpgProgram({ program: playingNow })); }This avoids the extra subscription entirely. Alternatively, if you prefer to keep using
items$, at least addtake(1)so each call tosetPlayingNowcompletes its subscription.
- Type-safety for “no program”
You’re intentionally dispatching
null/undefinedto clear the current program, butplayingNowis declared as a non-nullEpgProgramand is assigned viaplayingNow!. To better reflect the actual behavior, consider:- /** EPG selected program */ - playingNow!: EpgProgram; + /** EPG selected program (null when nothing is currently playing) */ + playingNow: EpgProgram | null = null;And then dispatch
program: playingNow(which can benull) instead of relying on an unsafe assertion.These adjustments keep the new “clear stale EPG” behavior while making the implementation safer and easier to reason about.
libs/ui/components/src/lib/channel-list-container/channel-list-item/channel-list-item.component.ts (1)
27-166: Consider stopping click propagation when toggling favoritesThe new layout, EPG display, and progress calculation look solid (OnPush +
markForCheck, interval cleanup, clamped percentage, etc.). One behavioral detail to double‑check:<div class="channel-list-item" ... (click)="clicked.emit()" > ... <button *ngIf="showFavoriteButton" mat-icon-button class="favorite-button" ... (click)="favoriteToggled.emit($event)" >Because the root div listens for
click, clicking the favorite button will also bubble up and triggerclicked.emit(), effectively selecting the channel when the user only intended to toggle the favorite.If you’d prefer these actions to be distinct, you can stop propagation on the button:
- (click)="favoriteToggled.emit($event)" + (click)="$event.stopPropagation(); favoriteToggled.emit($event)"This keeps the new UX while preventing accidental channel activation via the favorite button.
libs/ui/components/src/lib/info-overlay/info-overlay.component.ts (1)
88-101: Consider clarifying the toggle behavior.The
showOverlay()method has dual behavior: it toggles off immediately if already visible, or shows for 10 seconds if hidden. While functional, this might be unexpected for users triggering it multiple times. Consider either:
- Renaming to
toggleOverlay()to make the toggle behavior explicit- Always resetting the 10-second timer when called, rather than immediately hiding
Current behavior: pressing 'I' when overlay is visible → hides immediately
Alternative: pressing 'I' when overlay is visible → resets 10s timer and keeps visiblelibs/ui/components/src/lib/info-overlay/info-overlay.component.html (1)
1-71: Well-structured dual-layout approach.The template cleanly separates EPG and no-EPG states with consistent structure. The conditional rendering based on
epgProgramexistence is clear and maintains good visual consistency between states.Optional: The progress width calculation on line 41 could be extracted to a computed getter for better testability:
get progressWidth(): number { return (this.finishedDuration * 100) / this.generalDuration; }Then in template:
[ngStyle]="{ width: progressWidth + '%' }"libs/ui/components/src/lib/channel-list-container/channel-list-item/channel-list-item.component.scss (1)
2-2: Consider centralizing font imports.The Google Fonts import adds an external network dependency at the component level. Consider:
- Moving font imports to a global stylesheet to avoid duplicate requests (same fonts are imported in info-overlay component)
- Or using system fonts as fallbacks to reduce external dependencies
- Or preloading fonts in the HTML head for better performance
Current approach works but creates multiple font requests and blocks rendering until fonts load.
libs/ui/components/src/lib/channel-list-container/channel-list-container.component.ts (1)
125-142: Remove or guard console.log statements.The favorites$ logic correctly combines store favorites with the channel list. However, the console.log statements on lines 131 and 139 should be removed or placed behind a debug flag for production builds.
Apply this diff to remove the console statements:
favorites$ = combineLatest([ this.store.select(selectFavorites), this.channelList$, ]).pipe( map(([favoriteChannelIds, channelList]) => { - console.log('[ChannelList] favorites$ emit - IDs:', favoriteChannelIds.length, 'Channels:', channelList.length); const favorites = favoriteChannelIds .map((favoriteChannelId) => channelList.find( (channel) => channel.url === favoriteChannelId ) ) .filter((channel): channel is Channel => channel !== undefined); - console.log('[ChannelList] favorites$ result:', favorites.length, 'favorites'); return favorites; }) );libs/ui/components/src/lib/info-overlay/info-overlay.component.scss (2)
1-2: Consider self-hosting fonts for privacy and reliability.While the Google Fonts CDN is convenient, it introduces external dependencies that could impact privacy and availability. Using
display=swapis good, but consider self-hosting these fonts to:
- Eliminate third-party requests
- Improve privacy compliance (GDPR)
- Ensure reliability in offline scenarios
136-167: Consider adding ARIA attributes for progress bar accessibility.The progress bar looks great with its gradient fill and shimmer animation. However, for better accessibility, the HTML element using
.progress-fillshould include ARIA attributes likerole="progressbar",aria-valuenow,aria-valuemin, andaria-valuemaxso screen readers can announce the progress.Note: Since this is a SCSS file, you'll need to add these attributes in the corresponding HTML template.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (17)
apps/electron-backend/src/app/events/playlist.events.ts(1 hunks)apps/web/src/app/home/video-player/video-player.component.html(1 hunks)apps/web/src/app/home/video-player/video-player.component.ts(4 hunks)apps/web/src/assets/i18n/en.json(2 hunks)libs/m3u-state/src/lib/effects.ts(1 hunks)libs/services/src/lib/epg.service.ts(3 hunks)libs/ui/components/src/lib/channel-list-container/channel-list-container.component.html(7 hunks)libs/ui/components/src/lib/channel-list-container/channel-list-container.component.scss(3 hunks)libs/ui/components/src/lib/channel-list-container/channel-list-container.component.ts(5 hunks)libs/ui/components/src/lib/channel-list-container/channel-list-item/channel-list-item.component.scss(1 hunks)libs/ui/components/src/lib/channel-list-container/channel-list-item/channel-list-item.component.ts(2 hunks)libs/ui/components/src/lib/epg-list/epg-list.component.ts(1 hunks)libs/ui/components/src/lib/info-overlay/info-overlay.component.html(1 hunks)libs/ui/components/src/lib/info-overlay/info-overlay.component.scss(2 hunks)libs/ui/components/src/lib/info-overlay/info-overlay.component.ts(3 hunks)libs/ui/components/src/lib/video-player/toolbar/toolbar.component.html(2 hunks)libs/ui/components/src/lib/video-player/toolbar/toolbar.component.ts(1 hunks)
🔇 Additional comments (24)
libs/ui/components/src/lib/video-player/toolbar/toolbar.component.ts (1)
35-37: Toolbar input/output wiring for overlay looks consistent
isLeftDrawerOpenedandinfoOverlayClickedalign with the updated template usage and existing signal-style outputs. The wiring is straightforward and doesn’t introduce behavioral issues on its own.libs/ui/components/src/lib/video-player/toolbar/toolbar.component.html (1)
8-31: Menu icon binding and info button wiring look goodThe menu icon now responds to
isLeftDrawerOpened, and the new info button correctly emitsinfoOverlayClickedwith the appropriate localized tooltip and icon. This aligns with the updated toolbar component API and the overlay trigger flow.apps/web/src/assets/i18n/en.json (1)
197-198: LGTM!The new localization keys are well-named and the text is clear and user-friendly. The keyboard shortcut hint in SHOW_INFO is a nice touch for discoverability.
Also applies to: 213-213
apps/web/src/app/home/video-player/video-player.component.html (1)
19-21: LGTM!The new event binding and input property correctly wire up the info overlay toggle functionality and drawer state to the toolbar component.
libs/ui/components/src/lib/info-overlay/info-overlay.component.ts (1)
51-62: Proper null handling for EPG data.The enhanced logic correctly resets all EPG-related state when no program is available, preventing stale data from being displayed. This is essential for the no-EPG layout fallback.
libs/ui/components/src/lib/channel-list-container/channel-list-container.component.scss (2)
5-5: LGTM!The multiple
overflow-x: hiddendeclarations effectively prevent horizontal scrollbars across different container levels in the channel list, addressing the UI issue mentioned in the PR description.Also applies to: 24-24, 28-30
72-86: Good empty state styling.The empty favorites styling provides clear visual feedback with appropriate padding and font sizing.
libs/ui/components/src/lib/channel-list-container/channel-list-container.component.html (3)
26-26: LGTM!The
itemSize="68"aligns with the channel list item height defined in the SCSS (line 8 of channel-list-item.component.scss).
153-162: Good empty state UX.The empty favorites state provides helpful guidance to users with clear messaging.
44-44: No issues found—implementation already uses optimized caching.The
getEpgForChannelmethod performs a simpleMap.get()lookup, which is an O(1) operation. The EPG data is pre-computed and cached inchannelEpgMap(line 69), so there are no performance concerns. The implementation already follows best practices for this use case.apps/web/src/app/home/video-player/video-player.component.ts (1)
336-352: LGTM!The keyboard shortcut handler and toggle method are properly implemented. The
@HostListenercorrectly captures the 'I' key press and delegates to the overlay component'sshowOverlay()method.libs/ui/components/src/lib/channel-list-container/channel-list-item/channel-list-item.component.scss (1)
5-159: Comprehensive styling with good theme support.The BEM-like structure with dark theme support and EPG progress visualization is well-implemented. The gradient progress bar with animation provides good visual feedback.
libs/ui/components/src/lib/channel-list-container/channel-list-container.component.ts (6)
15-15: LGTM!The lifecycle hooks and imports are correctly implemented.
Also applies to: 36-36, 38-38, 62-62
68-79: LGTM!The EPG state management fields are well-typed. The use of
Map<string, EpgProgram | null>correctly handles channels with and without EPG data.
86-92: LGTM!The channelList setter correctly propagates changes through the observable stream and triggers EPG fetching. The EPG service's caching layer (60-second TTL) will prevent excessive backend calls even if the setter is invoked frequently.
187-192: LGTM!The EPG refresh interval is correctly implemented with proper cleanup. The 60-second interval is reasonable for EPG data freshness, and the caching layer in EpgService prevents redundant backend calls.
194-203: LGTM!Proper cleanup of resources: the interval is cleared and the BehaviorSubject is completed, preventing memory leaks.
231-237: LGTM!The helper method correctly retrieves EPG data from the map with proper null/undefined handling.
libs/services/src/lib/epg.service.ts (3)
4-4: LGTM!The caching layer is well-designed with proper encapsulation. The 60-second TTL is appropriate for EPG data freshness, and using a Map provides efficient O(1) lookups.
Also applies to: 8-25
174-185: LGTM!The current program logic correctly identifies the program airing at the current time using inclusive time boundaries.
255-260: LGTM!The cache clearing utility is straightforward and well-documented.
libs/ui/components/src/lib/info-overlay/info-overlay.component.scss (3)
4-31: LGTM!The blur effect implementation is well-crafted:
isolation: isolateproperly contains the blur- Vendor prefixes (
-webkit-) ensure Safari compatibility- Using
::beforewithz-index: -1correctly layers the blur behind contentNote:
backdrop-filterrequires modern browsers; older browsers will see the overlay without blur, which degrades gracefully.
33-95: LGTM!The EPG layout is well-structured with:
- Proper flexbox composition and text truncation (
min-width: 0)- Staggered animations for a polished reveal
- Clear typographic hierarchy using custom fonts
- Good use of shadows for depth and readability
169-220: LGTM!The animations are well-implemented:
- Smooth, performance-friendly transforms
- Appropriate timing and easing functions
- Clear separation between EPG and no-EPG states with helpful comments
The
.hiddenclass's 2-second delay (line 207) pairs well with the PR's 10-second auto-hide behavior.
libs/ui/components/src/lib/channel-list-container/channel-list-container.component.ts
Show resolved
Hide resolved
efee5ea to
a3f056d
Compare
ec89b58 to
b8d9fad
Compare
45204a2 to
a26978d
Compare
a3f056d to
b88078c
Compare
a26978d to
a7b535b
Compare
Introduce a separate no-EPG presentation and move backdrop blur into an isolated pseudo-element to avoid visual bleed and improve layout control. - Replace direct backdrop-filter on the overlay with a ::before pseudo-element that applies backdrop-filter and mask-image gradients (with -webkit- prefixed fallbacks) for a smoother gradient blur effect. - Add isolation on the overlay to contain stacking context and set z-index of the pseudo-element to -1 to keep content above the blur. - Add .no-epg modifier on the overlay and new .no-epg-layout, .channel-logo-large and .channel-name-large styles to provide a centered, accessible layout when no EPG data is available. - Update template to render two distinct layouts: one when epgProgram exists (original detailed view) and one fallback view when epgProgram is missing, including larger channel logo and centered channel name. These changes improve visual fidelity of the blur effect and add a clear fallback UI for channels without EPG data.
Refactor the info-overlay template to introduce a structured EPG layout: replace the previous flat channel-logo + content structure with an .epg-layout wrapper that groups .channel-logo and a richer .content area. Split content into .content-header (separate program title and channel name), conditional program description rendering, and a program-timeline containing explicit start/end times and a progress track. Remove fixed image width attribute and rely on responsive CSS. Revamp component SCSS: import refined fonts, increase overlay max-height, add horizontal padding, and add new styles for .epg-layout, .channel-logo, .content, .content-header, .program-title and related elements. Add animations, improved image handling (object-fit + drop shadow), and layout spacing to support varying content lengths and improve visual hierarchy. These changes improve responsiveness, accessibility of EPG text display, and visual polish of the overlay.
b88078c to
0823af2
Compare
a7b535b to
40e9006
Compare
Reset EPG fields when epgProgram becomes null to avoid stale displayed durations and ensure consistent behavior when no program is available. Improve channel list container and item styling: - hide horizontal overflow to prevent unexpected scrollbars (scroll-viewport, #all-channels, .channel-list). - add empty-favorites layout and hint styles for clearer empty state presentation. - refactor channel-list-item SCSS: introduce structured layout (.channel-list-item, .channel-content, .channel-logo, .channel-details), apply responsive truncation rules and font imports, add hover/active visuals and dark-theme support, and tweak drag-icon spacing. These changes fix UI glitches (stale EPG, horizontal scrollbars) and modernize the channel list presentation for better readability and theming.
Add "Show program info (Press I)" translation and an info icon button to the video player toolbar. Emit an infoOverlayClicked event from the toolbar and expose isLeftDrawerOpened to control the menu icon state. Update the menu icon to reflect drawer open/closed state. Implement showOverlay() on the info overlay component to toggle visibility and auto-hide after 10 seconds when shown. This enables manual toggling of the program info overlay via the new toolbar button or keyboard shortcut, improving discoverability and user control of program information.
Add a transient channel number overlay to the video player UI so users see the numeric channel feedback when entering or changing channels. - Insert conditional overlay markup in the video-player template that renders when showChannelNumberOverlay is true and displays the channelNumberInput value. - Add styles for .channel-number-overlay and .channel-number-display to center the overlay, style the numeric display (large bold font, dark translucent background, rounded corners, shadow) and include a brief scale-in animation. - Keep overlay pointer-events disabled so it doesn't block player input. This improves user experience by giving clear visual confirmation of channel changes.
Add compact layout support for channel list items and make EPG display conditional based on runtime environment and stored settings. - Introduce .compact styles in channel-list-item.component.scss to reduce item height, padding, and logo size when EPG is hidden. - Add StorageMap injection and read STORE_KEY.Settings in ChannelListContainerComponent to determine whether EPG is configured (only enable EPG in Electron when epgUrl exists; disable in PWA). - Expose shouldShowEpg flag and itemSize getter to switch virtual scroll item size between 68 and 48 pixels. - Bind [class.compact] on channel list item and wire [showEpg] input to channel-list-item components so item rendering adapts to mode. - Replace hardcoded itemSize in cdk-virtual-scroll-viewport with dynamic [itemSize] to match compact/expanded layouts. This reduces visual clutter and avoids showing EPG in environments (where it is not configured or supported), improving UX and resource usage.
Revamp the Multi-EPG component stylesheet to introduce a polished, broadcast-control-room inspired dark theme and improved layout styling. - Add Google fonts (Outfit, JetBrains Mono) for a clean UI and mono date display. - Introduce color variables, gradients and accents for consistent theming and easier maintenance. - Rework base container (.parent) with subtle grid overlay and updated typography. - Implement a frosted glass navigation bar (#epg-navigation) with blur, glow, and accessible button styles. - Add today-date styling using a monospace font and glowing accent. - Expand channels column width, update background, borders, shadows, and hover transitions for clearer channel separation. - Replace many hard-coded colors with variables and add transitions for smoother interactions. - Add utility classes for navigation buttons and improved disabled/ hover states. These changes improve visual hierarchy, accessibility, and maintainabiity of the EPG UI while setting up a consistent design system for further enhancements.
Add explicit icon settings to packaged app configuration for macOS, Linux and Windows. Set macOS icon to apps/web/src/assets/icons/favicon.ic, Linux icon directory to apps/web/src/assets/icons and Windows icon to apps/web/src/assets/icons/favicon.ico. This ensures bundled installers and app bundles include the intended application icon across platforms and prevents missing icon assets when creating artifacts. Also add trailing commas to keep JSON formatting consistent.
Adjust documentation lists and code blocks for consistent indentation and spacing across CLAUDE.md. Convert mixed dash and nested list levels to use uniform two-space indentation for subitems, reflow a few wrapped lines, and add blank lines where needed to separate sections and examples. These changes improve readability and maintain a consistent markdown structure for the project documentation.
40e9006 to
0b31aac
Compare
0291fa8
into
feat-remote-control-ui-server-integration
Summary
This is part 2 of 2 in a stack made with GitButler:
Summary by CodeRabbit
Release Notes