diff --git a/libs/playlist/shared/ui/src/lib/playlist-switcher/playlist-switcher.component.html b/libs/playlist/shared/ui/src/lib/playlist-switcher/playlist-switcher.component.html
index a50c6a083..c1e4f79c9 100644
--- a/libs/playlist/shared/ui/src/lib/playlist-switcher/playlist-switcher.component.html
+++ b/libs/playlist/shared/ui/src/lib/playlist-switcher/playlist-switcher.component.html
@@ -56,32 +56,40 @@
}
-
-
-
-
-
+ @if (showTypeFilters()) {
+
+ @if (hasType('m3u')) {
+
+ }
+ @if (hasType('stalker')) {
+
+ }
+ @if (hasType('xtream')) {
+
+ }
+
+ }
+
+
} @empty {
@@ -144,17 +164,17 @@
}
- @if (showPlaylistInfo() || showAccountInfo()) {
+ @if (showAddPlaylist() || showAccountInfo()) {
- @if (showPlaylistInfo()) {
+ @if (showAddPlaylist()) {
}
@@ -172,3 +192,29 @@
}
+
+
diff --git a/libs/playlist/shared/ui/src/lib/playlist-switcher/playlist-switcher.component.scss b/libs/playlist/shared/ui/src/lib/playlist-switcher/playlist-switcher.component.scss
index a16f2d061..9b9ed1119 100644
--- a/libs/playlist/shared/ui/src/lib/playlist-switcher/playlist-switcher.component.scss
+++ b/libs/playlist/shared/ui/src/lib/playlist-switcher/playlist-switcher.component.scss
@@ -103,15 +103,15 @@
::ng-deep .playlist-switcher-menu.mat-mdc-menu-panel {
--mat-menu-container-color: var(--mat-sys-surface-container-high);
width: min(
- var(--playlist-switcher-overlay-width, 320px),
+ var(--playlist-switcher-overlay-width, 360px),
calc(100vw - 24px)
) !important;
min-width: min(
- var(--playlist-switcher-overlay-width, 320px),
+ var(--playlist-switcher-overlay-width, 360px),
calc(100vw - 24px)
) !important;
max-width: min(
- var(--playlist-switcher-overlay-width, 320px),
+ var(--playlist-switcher-overlay-width, 360px),
calc(100vw - 24px)
) !important;
margin-top: -1px !important;
@@ -276,12 +276,55 @@
.playlist-item.selected {
background: var(--app-selection-surface, rgba(139, 92, 246, 0.1));
+ &::before {
+ content: '';
+ position: absolute;
+ left: 0;
+ top: 8px;
+ bottom: 8px;
+ width: 3px;
+ border-radius: 0 3px 3px 0;
+ background: var(--app-selection-color, #a78bfa);
+ }
+
.playlist-title,
.playlist-meta {
color: var(--app-selection-color, #a78bfa);
}
}
+.item-action-trigger {
+ opacity: 0;
+ pointer-events: none;
+ transition: opacity 0.15s ease;
+ width: 32px;
+ height: 32px;
+ line-height: 32px;
+ flex-shrink: 0;
+ color: var(--mat-sys-on-surface-variant);padding: 0;
+
+ mat-icon {
+ font-size: 18px;
+ width: 18px;
+ height: 18px;
+ }
+}
+
+.playlist-item:hover .item-action-trigger,
+.playlist-item.selected .item-action-trigger,
+.item-action-trigger:focus-visible,
+.item-action-trigger[aria-expanded='true'] {
+ opacity: 1;
+ pointer-events: auto;
+}
+
+::ng-deep .playlist-item-action-menu {
+ .danger,
+ .danger mat-icon {
+ color: var(--mat-sys-error, #f44336);
+ }
+}
+
.playlist-item:hover:not(.selected) {
background: color-mix(
in srgb,
diff --git a/libs/playlist/shared/ui/src/lib/playlist-switcher/playlist-switcher.component.ts b/libs/playlist/shared/ui/src/lib/playlist-switcher/playlist-switcher.component.ts
index bf279a7ee..9d106ceb4 100644
--- a/libs/playlist/shared/ui/src/lib/playlist-switcher/playlist-switcher.component.ts
+++ b/libs/playlist/shared/ui/src/lib/playlist-switcher/playlist-switcher.component.ts
@@ -14,16 +14,29 @@ import { toSignal } from '@angular/core/rxjs-interop';
import { FormsModule } from '@angular/forms';
import { MatIconButton } from '@angular/material/button';
import { MatRippleModule } from '@angular/material/core';
+import { MatDialog } from '@angular/material/dialog';
import { MatDivider } from '@angular/material/divider';
import { MatIcon } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input';
import { MatMenu, MatMenuModule, MatMenuTrigger } from '@angular/material/menu';
+import { MatSnackBar } from '@angular/material/snack-bar';
+import { Store } from '@ngrx/store';
import { normalizeDateLocale } from '@iptvnator/pipes';
import { TranslatePipe, TranslateService } from '@ngx-translate/core';
-import { PlaylistContextFacade } from '@iptvnator/playlist/shared/util';
-import { PortalStatus, PortalStatusService } from 'services';
+import { DialogService } from 'components';
+import { PlaylistActions } from 'm3u-state';
+import {
+ PlaylistContextFacade,
+ PlaylistRefreshActionService,
+} from '@iptvnator/playlist/shared/util';
+import {
+ DatabaseService,
+ PortalStatus,
+ PortalStatusService,
+} from 'services';
import { PlaylistMeta } from 'shared-interfaces';
import { startWith } from 'rxjs';
+import { PlaylistInfoComponent } from '../recent-playlists/playlist-info/playlist-info.component';
type PlaylistFilterType = 'm3u' | 'stalker' | 'xtream';
@@ -57,6 +70,12 @@ export class PlaylistSwitcherComponent {
private readonly playlistContext = inject(PlaylistContextFacade);
private readonly portalStatusService = inject(PortalStatusService);
private readonly translate = inject(TranslateService);
+ private readonly refreshAction = inject(PlaylistRefreshActionService);
+ private readonly dialog = inject(MatDialog);
+ private readonly dialogService = inject(DialogService);
+ private readonly databaseService = inject(DatabaseService);
+ private readonly snackBar = inject(MatSnackBar);
+ private readonly store = inject(Store);
private focusSearchTimeoutId: ReturnType | null = null;
private readonly languageTick = toSignal(
this.translate.onLangChange.pipe(startWith(null)),
@@ -67,9 +86,11 @@ export class PlaylistSwitcherComponent {
readonly subtitle = input('');
readonly showPlaylistInfo = input(false);
readonly showAccountInfo = input(false);
+ readonly showAddPlaylist = input(false);
readonly playlistSelected = output();
readonly playlistInfoRequested = output();
readonly accountInfoRequested = output();
+ readonly addPlaylistRequested = output();
readonly menuTrigger = viewChild.required('menuTrigger');
readonly playlistMenu = viewChild.required('playlistMenu');
@@ -123,6 +144,17 @@ export class PlaylistSwitcherComponent {
);
});
+ readonly availablePlaylistTypes = computed(() => {
+ const types = new Set();
+ for (const playlist of this.playlists()) {
+ types.add(this.getPlaylistFilterType(playlist));
+ }
+ return types;
+ });
+ readonly showTypeFilters = computed(
+ () => this.availablePlaylistTypes().size > 1
+ );
+
readonly portalStatuses = signal