mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-09 09:26:14 -08:00
fix(ui): one provider icon per playlist row, imperative Korean remove label
A restored Stalker or Xtream playlist can also carry a URL, and the row's independent checks then showed the M3U URL icon next to the provider icon. The row now switches on resolvePlaylistSourceIconKey(), the precedence every other surface uses, so each source shows exactly one icon. HOME.PLAYLISTS.REMOVE now names the confirm button and the row's delete tooltip; in Korean it read "the playlist has been removed". It now says "remove playlist", like every other locale. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
082c56608b
commit
fb293ea23d
4 files changed
+98
-57
No files matched your search
@@ -65,7 +65,7 @@
|
||||
"CHANNELS": "채널",
|
||||
"ADDED": "추가되었습니다",
|
||||
"SHOW_DETAILS": "재생 목록 세부 정보 표시",
|
||||
"REMOVE": "재생 목록이 제거되었습니다",
|
||||
"REMOVE": "재생 목록 제거",
|
||||
"SEARCH_PLAYLISTS": "제목으로 재생목록 검색",
|
||||
"INFO_DIALOG": {
|
||||
"PLAYLIST_DETAILS": "재생 목록 세부 사항",
|
||||
|
||||
+55
-56
@@ -17,69 +17,68 @@
|
||||
[enabled]="!isBusy()"
|
||||
/>
|
||||
}
|
||||
@if (item.url) {
|
||||
<div class="icon-container">
|
||||
<!-- One provider icon per row, by the shared precedence: a restored
|
||||
Stalker or Xtream playlist can also carry a URL. -->
|
||||
@switch (sourceIconKey) {
|
||||
@case ('stalker') {
|
||||
<mat-icon
|
||||
class="upload-type-icon"
|
||||
[matTooltip]="
|
||||
('HOME.PLAYLISTS.ADDED_VIA_URL' | translate) +
|
||||
' ' +
|
||||
item.url
|
||||
"
|
||||
>{{ sourceIcons['m3u-url'] }}</mat-icon
|
||||
[matTooltip]="'HOME.PLAYLISTS.STALKER_PORTAL' | translate"
|
||||
>{{ sourceIcons.stalker }}</mat-icon
|
||||
>
|
||||
@if (item.autoRefresh) {
|
||||
}
|
||||
@case ('xtream') {
|
||||
<div class="icon-container">
|
||||
<mat-icon
|
||||
class="auto-refresh-indicator"
|
||||
class="upload-type-icon"
|
||||
[matTooltip]="
|
||||
'HOME.PLAYLISTS.AUTO_REFRESH_ENABLED' | translate
|
||||
'HOME.PLAYLISTS.XTREAM_PLAYLIST' | translate
|
||||
"
|
||||
>autorenew</mat-icon
|
||||
>{{ sourceIcons.xtream }}</mat-icon
|
||||
>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
@if (!item.url && !item.serverUrl && !item.macAddress) {
|
||||
<div class="icon-container">
|
||||
<mat-icon
|
||||
class="upload-type-icon"
|
||||
[matTooltip]="'HOME.PLAYLISTS.ADDED_VIA_FILE' | translate"
|
||||
>{{ sourceIcons['m3u-local'] }}</mat-icon
|
||||
>
|
||||
@if (item.autoRefresh) {
|
||||
<mat-icon
|
||||
class="auto-refresh-indicator"
|
||||
[matTooltip]="
|
||||
'HOME.PLAYLISTS.AUTO_REFRESH_ENABLED' | translate
|
||||
"
|
||||
>autorenew</mat-icon
|
||||
>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
@if (item.serverUrl) {
|
||||
<div class="icon-container">
|
||||
<mat-icon
|
||||
class="upload-type-icon"
|
||||
[matTooltip]="'HOME.PLAYLISTS.XTREAM_PLAYLIST' | translate"
|
||||
>{{ sourceIcons.xtream }}</mat-icon
|
||||
>
|
||||
@if (!runtime.supportsSourceHealth) {
|
||||
<span
|
||||
class="status-dot"
|
||||
[class]="getStatusClass()"
|
||||
[matTooltip]="'Portal status: ' + portalStatus"
|
||||
[attr.aria-label]="'Portal status: ' + portalStatus"
|
||||
></span>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
@if (item.macAddress) {
|
||||
<mat-icon
|
||||
class="upload-type-icon"
|
||||
[matTooltip]="'HOME.PLAYLISTS.STALKER_PORTAL' | translate"
|
||||
>{{ sourceIcons.stalker }}</mat-icon
|
||||
>
|
||||
@if (!runtime.supportsSourceHealth) {
|
||||
<span
|
||||
class="status-dot"
|
||||
[class]="getStatusClass()"
|
||||
[matTooltip]="'Portal status: ' + portalStatus"
|
||||
[attr.aria-label]="'Portal status: ' + portalStatus"
|
||||
></span>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
@default {
|
||||
<div class="icon-container">
|
||||
@if (sourceIconKey === 'm3u-url') {
|
||||
<mat-icon
|
||||
class="upload-type-icon"
|
||||
[matTooltip]="
|
||||
('HOME.PLAYLISTS.ADDED_VIA_URL' | translate) +
|
||||
' ' +
|
||||
item.url
|
||||
"
|
||||
>{{ sourceIcons['m3u-url'] }}</mat-icon
|
||||
>
|
||||
} @else {
|
||||
<mat-icon
|
||||
class="upload-type-icon"
|
||||
[matTooltip]="
|
||||
'HOME.PLAYLISTS.ADDED_VIA_FILE' | translate
|
||||
"
|
||||
>{{ sourceIcons['m3u-local'] }}</mat-icon
|
||||
>
|
||||
}
|
||||
@if (item.autoRefresh) {
|
||||
<mat-icon
|
||||
class="auto-refresh-indicator"
|
||||
[matTooltip]="
|
||||
'HOME.PLAYLISTS.AUTO_REFRESH_ENABLED'
|
||||
| translate
|
||||
"
|
||||
>autorenew</mat-icon
|
||||
>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
<div class="playlist-content">
|
||||
|
||||
+36
@@ -221,4 +221,40 @@ describe('PlaylistItemComponent', () => {
|
||||
).toContain('42%');
|
||||
expect(nativeElement.querySelector('.cancel-btn')).not.toBeNull();
|
||||
});
|
||||
|
||||
it.each([
|
||||
[
|
||||
{ macAddress: '00:1A:79:00:00:01', url: 'http://portal.test' },
|
||||
'cast',
|
||||
],
|
||||
[
|
||||
{ serverUrl: 'http://xtream.test', url: 'http://xtream.test' },
|
||||
'cloud',
|
||||
],
|
||||
[{ url: 'http://list.test/playlist.m3u' }, 'link'],
|
||||
[{}, 'description'],
|
||||
])(
|
||||
'shows one provider icon for %o, with the shared precedence',
|
||||
(source, icon) => {
|
||||
fixture.destroy();
|
||||
fixture = TestBed.createComponent(PlaylistItemComponent);
|
||||
fixture.componentInstance.item = {
|
||||
title: 'Source',
|
||||
_id: 'source',
|
||||
count: 10,
|
||||
importDate: Date.now().toString(),
|
||||
autoRefresh: false,
|
||||
...source,
|
||||
};
|
||||
fixture.detectChanges();
|
||||
|
||||
const icons = Array.from(
|
||||
(fixture.nativeElement as HTMLElement).querySelectorAll(
|
||||
'.upload-type-icon'
|
||||
),
|
||||
(element) => element.textContent?.trim()
|
||||
);
|
||||
expect(icons).toEqual([icon]);
|
||||
}
|
||||
);
|
||||
});
|
||||
+6
@@ -1,6 +1,8 @@
|
||||
import { Injector } from '@angular/core';
|
||||
import { SourceHealthService } from '@iptvnator/portal/shared/data-access';
|
||||
import {
|
||||
PlaylistSourceIconKey,
|
||||
resolvePlaylistSourceIconKey,
|
||||
SOURCE_TYPE_ICONS,
|
||||
sourceHealthType,
|
||||
} from '@iptvnator/shared/interfaces';
|
||||
@@ -72,6 +74,10 @@ export class PlaylistItemComponent implements OnInit {
|
||||
private readonly portalStatusService = inject(PortalStatusService);
|
||||
readonly runtime = inject(RuntimeCapabilitiesService);
|
||||
readonly sourceIcons = SOURCE_TYPE_ICONS;
|
||||
|
||||
get sourceIconKey(): PlaylistSourceIconKey {
|
||||
return resolvePlaylistSourceIconKey(this.item);
|
||||
}
|
||||
private readonly translate = inject(TranslateService);
|
||||
private readonly languageTick = toSignal(
|
||||
this.translate.onLangChange.pipe(startWith(null)),
|
||||
|
||||
Reference in new issue
Block a user