feat(xtream): catch-up badge for live channels with archive (#1341)

* feat(xtream): show a catch-up badge on live channels that have archive

Live channels whose provider declares playable catch-up (tv_archive=1
with a positive tv_archive_duration) now show a small history badge in
the channel sidebar next to the name and on the all-channels grid cards,
with the archive window (days) in the tooltip.

Closes #1128

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

* fix(xtream): expose the catch-up badge status to assistive technology

The mat-icon is aria-hidden and the tooltip is pointer-only, so the
badge status was invisible to keyboard and screen-reader users. Both
badge surfaces now also render the translated status as visually-hidden
text (Codex review, P2).

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

* feat(xtream): show the catch-up badge in favorites and recent lists

Carries tvArchive/tvArchiveDuration through UnifiedFavoriteChannel so
the shared favorites list (portal favorites/recent tabs and global
favorites) renders the same catch-up badge as the live sidebar.
Requested in PR feedback by the issue author.

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

* feat(ui): show the programme-info button in portal sidebars, stacked vertically

Adds the (i) programme-info button to the Xtream and Stalker live
sidebars and reworks the row action column: buttons stack vertically
(favorite on top, info below), so the second button costs no horizontal
space — the column is actually narrower than the previous single-button
row. The info slot is reserved (inert, visibility:hidden) while the row
has no programme, so the star never shifts when EPG data arrives.
Requested by the issue author in PR feedback.

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

* test(ui): move the archive passthrough spec out of the budget-capped file

CI lints the merge with master, where unified-live-tab.component.spec.ts
grew (#1374) to one line under the 1200 max-lines test budget — the
archive passthrough test added here tipped the merged result over. The
test moves to a focused template-less spec (plus a null-normalisation
case), leaving the main spec at master's size.

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

* fix(ui): constrain Material touch targets to the stacked button bounds

mat-icon-button keeps a 48px touch target; stacked 28px buttons
overlapped by 20px and the later sibling (programme info) stole clicks
from the lower third of the favorite star. Verified via
document.elementFromPoint before/after: the star's visual bounds now hit
the star, and clicks left of the column reach the row again instead of
the button's oversized target (Codex review).

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

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
4grayandClaude Fable 5 authored and GitHub committed 2026-08-09 10:47:44 +02:00
1 parent 87dc45957b
commit d5f84fb130
42 files changed
+689 -22

No files matched your search

+2
View File
@@ -635,6 +635,8 @@
"NO_SEARCH_RESULTS": "لم يتم العثور على قنوات",
"NO_CHANNELS_FOUND": "لم يتم العثور على قنوات",
"NO_GROUPS_FOUND": "لم يتم العثور على مجموعات",
"CATCHUP_AVAILABLE": "Catchup متاح",
"CATCHUP_AVAILABLE_DAYS": "Catchup متاح — {{days}} يوم",
"TRY_DIFFERENT_SEARCH": "جرّب مصطلح بحث مختلف",
"DETAILS_DIALOG": {
"TITLE": "تفاصيل القناة",
+2
View File
@@ -635,6 +635,8 @@
"NO_SEARCH_RESULTS": "ما تلقاتش حتى قناة",
"NO_CHANNELS_FOUND": "ما تلقاتش حتى قناة",
"NO_GROUPS_FOUND": "ما تلقاتش حتى مجموعة",
"CATCHUP_AVAILABLE": "Catchup متوفر",
"CATCHUP_AVAILABLE_DAYS": "Catchup متوفر — {{days}} يوم",
"TRY_DIFFERENT_SEARCH": "جرب كلمة بحث أخرى",
"DETAILS_DIALOG": {
"TITLE": "تفاصيل القناة",
+2
View File
@@ -635,6 +635,8 @@
"NO_SEARCH_RESULTS": "Каналаў не знойдзена",
"NO_CHANNELS_FOUND": "Каналаў не знойдзена",
"NO_GROUPS_FOUND": "Груп не знойдзена",
"CATCHUP_AVAILABLE": "Catchup даступны",
"CATCHUP_AVAILABLE_DAYS": "Catchup даступны — {{days}} дзён",
"TRY_DIFFERENT_SEARCH": "Паспрабуйце іншы пошукавы запыт",
"DETAILS_DIALOG": {
"TITLE": "Інфармацыя аб канале",
+2
View File
@@ -635,6 +635,8 @@
"NO_SEARCH_RESULTS": "Keine Sender gefunden",
"NO_CHANNELS_FOUND": "Keine Sender gefunden",
"NO_GROUPS_FOUND": "Keine Gruppen gefunden",
"CATCHUP_AVAILABLE": "Catchup verfügbar",
"CATCHUP_AVAILABLE_DAYS": "Catchup verfügbar — {{days}} Tage",
"TRY_DIFFERENT_SEARCH": "Versuchen Sie einen anderen Suchbegriff",
"DETAILS_DIALOG": {
"TITLE": "Senderdetails",
+2
View File
@@ -635,6 +635,8 @@
"NO_SEARCH_RESULTS": "Δεν βρέθηκαν κανάλια",
"NO_CHANNELS_FOUND": "Δεν βρέθηκαν κανάλια",
"NO_GROUPS_FOUND": "Δεν βρέθηκαν ομάδες",
"CATCHUP_AVAILABLE": "Διαθέσιμο Catchup",
"CATCHUP_AVAILABLE_DAYS": "Διαθέσιμο Catchup — {{days}} ημέρες",
"TRY_DIFFERENT_SEARCH": "Δοκιμάστε διαφορετικό όρο αναζήτησης",
"DETAILS_DIALOG": {
"TITLE": "Λεπτομέρειες καναλιού",
+2
View File
@@ -635,6 +635,8 @@
"NO_SEARCH_RESULTS": "No channels found",
"NO_CHANNELS_FOUND": "No channels found",
"NO_GROUPS_FOUND": "No groups found",
"CATCHUP_AVAILABLE": "Catchup available",
"CATCHUP_AVAILABLE_DAYS": "Catchup available — {{days}} days",
"TRY_DIFFERENT_SEARCH": "Try a different search term",
"DETAILS_DIALOG": {
"TITLE": "Channel details",
+2
View File
@@ -635,6 +635,8 @@
"NO_SEARCH_RESULTS": "No se encontraron canales",
"NO_CHANNELS_FOUND": "No se encontraron canales",
"NO_GROUPS_FOUND": "No se encontraron grupos",
"CATCHUP_AVAILABLE": "Catchup disponible",
"CATCHUP_AVAILABLE_DAYS": "Catchup disponible — {{days}} días",
"TRY_DIFFERENT_SEARCH": "Prueba con otro término de búsqueda",
"DETAILS_DIALOG": {
"TITLE": "Detalles del canal",
+2
View File
@@ -635,6 +635,8 @@
"NO_SEARCH_RESULTS": "Aucune chaîne trouvée",
"NO_CHANNELS_FOUND": "Aucune chaîne trouvée",
"NO_GROUPS_FOUND": "Aucun groupe trouvé",
"CATCHUP_AVAILABLE": "Catchup disponible",
"CATCHUP_AVAILABLE_DAYS": "Catchup disponible — {{days}} jours",
"TRY_DIFFERENT_SEARCH": "Essayez un autre terme de recherche",
"DETAILS_DIALOG": {
"TITLE": "Détails de la chaîne",
+2
View File
@@ -635,6 +635,8 @@
"NO_SEARCH_RESULTS": "Nem található csatorna",
"NO_CHANNELS_FOUND": "Nem található csatorna",
"NO_GROUPS_FOUND": "Nem található csoport",
"CATCHUP_AVAILABLE": "Visszanézés elérhető",
"CATCHUP_AVAILABLE_DAYS": "Visszanézés elérhető — {{days}} nap",
"TRY_DIFFERENT_SEARCH": "Próbálkozzon másik keresési kifejezéssel",
"DETAILS_DIALOG": {
"TITLE": "Csatorna részletei",
+2
View File
@@ -635,6 +635,8 @@
"NO_SEARCH_RESULTS": "Nessun canale trovato",
"NO_CHANNELS_FOUND": "Nessun canale trovato",
"NO_GROUPS_FOUND": "Nessun gruppo trovato",
"CATCHUP_AVAILABLE": "Catchup disponibile",
"CATCHUP_AVAILABLE_DAYS": "Catchup disponibile — {{days}} giorni",
"TRY_DIFFERENT_SEARCH": "Prova con un altro termine di ricerca",
"DETAILS_DIALOG": {
"TITLE": "Dettagli canale",
+2
View File
@@ -635,6 +635,8 @@
"NO_SEARCH_RESULTS": "チャンネルが見つかりません",
"NO_CHANNELS_FOUND": "チャンネルが見つかりません",
"NO_GROUPS_FOUND": "グループが見つかりません",
"CATCHUP_AVAILABLE": "Catchup利用可能",
"CATCHUP_AVAILABLE_DAYS": "Catchup利用可能 — {{days}}日",
"TRY_DIFFERENT_SEARCH": "別の検索キーワードをお試しください",
"DETAILS_DIALOG": {
"TITLE": "チャンネルの詳細",
+2
View File
@@ -635,6 +635,8 @@
"NO_SEARCH_RESULTS": "채널을 찾을 수 없습니다",
"NO_CHANNELS_FOUND": "채널을 찾을 수 없습니다",
"NO_GROUPS_FOUND": "그룹을 찾을 수 없습니다",
"CATCHUP_AVAILABLE": "Catchup 사용 가능",
"CATCHUP_AVAILABLE_DAYS": "Catchup 사용 가능 — {{days}}일",
"TRY_DIFFERENT_SEARCH": "다른 검색어를 시도해 보세요",
"DETAILS_DIALOG": {
"TITLE": "채널 세부정보",
+2
View File
@@ -635,6 +635,8 @@
"NO_SEARCH_RESULTS": "Geen kanalen gevonden",
"NO_CHANNELS_FOUND": "Geen kanalen gevonden",
"NO_GROUPS_FOUND": "Geen groepen gevonden",
"CATCHUP_AVAILABLE": "Catchup beschikbaar",
"CATCHUP_AVAILABLE_DAYS": "Catchup beschikbaar — {{days}} dagen",
"TRY_DIFFERENT_SEARCH": "Probeer een andere zoekterm",
"DETAILS_DIALOG": {
"TITLE": "Kanaaldetails",
+2
View File
@@ -635,6 +635,8 @@
"NO_SEARCH_RESULTS": "Nie znaleziono kanałów",
"NO_CHANNELS_FOUND": "Nie znaleziono kanałów",
"NO_GROUPS_FOUND": "Nie znaleziono grup",
"CATCHUP_AVAILABLE": "Catchup dostępny",
"CATCHUP_AVAILABLE_DAYS": "Catchup dostępny — {{days}} dni",
"TRY_DIFFERENT_SEARCH": "Spróbuj innego zapytania",
"DETAILS_DIALOG": {
"TITLE": "Szczegóły kanału",
+2
View File
@@ -635,6 +635,8 @@
"NO_SEARCH_RESULTS": "Nenhum canal encontrado",
"NO_CHANNELS_FOUND": "Nenhum canal encontrado",
"NO_GROUPS_FOUND": "Nenhum grupo encontrado",
"CATCHUP_AVAILABLE": "Catchup disponível",
"CATCHUP_AVAILABLE_DAYS": "Catchup disponível — {{days}} dias",
"TRY_DIFFERENT_SEARCH": "Tente um termo de pesquisa diferente",
"DETAILS_DIALOG": {
"TITLE": "Detalhes do canal",
+2
View File
@@ -635,6 +635,8 @@
"NO_SEARCH_RESULTS": "Каналы не найдены",
"NO_CHANNELS_FOUND": "Каналы не найдены",
"NO_GROUPS_FOUND": "Группы не найдены",
"CATCHUP_AVAILABLE": "Catchup доступен",
"CATCHUP_AVAILABLE_DAYS": "Catchup доступен — {{days}} дн.",
"TRY_DIFFERENT_SEARCH": "Попробуйте другой поисковый запрос",
"DETAILS_DIALOG": {
"TITLE": "Сведения о канале",
+2
View File
@@ -635,6 +635,8 @@
"NO_SEARCH_RESULTS": "Kanal bulunamadı",
"NO_CHANNELS_FOUND": "Kanal bulunamadı",
"NO_GROUPS_FOUND": "Grup bulunamadı",
"CATCHUP_AVAILABLE": "Catchup mevcut",
"CATCHUP_AVAILABLE_DAYS": "Catchup mevcut — {{days}} gün",
"TRY_DIFFERENT_SEARCH": "Farklı bir arama terimi deneyin",
"DETAILS_DIALOG": {
"TITLE": "Kanal ayrıntıları",
+2
View File
@@ -635,6 +635,8 @@
"NO_SEARCH_RESULTS": "未找到频道",
"NO_CHANNELS_FOUND": "未找到频道",
"NO_GROUPS_FOUND": "未找到分组",
"CATCHUP_AVAILABLE": "Catchup 可用",
"CATCHUP_AVAILABLE_DAYS": "Catchup 可用 — {{days}} 天",
"TRY_DIFFERENT_SEARCH": "尝试其他搜索词",
"DETAILS_DIALOG": {
"TITLE": "频道详情",
+2
View File
@@ -635,6 +635,8 @@
"NO_SEARCH_RESULTS": "找不到頻道",
"NO_CHANNELS_FOUND": "找不到頻道",
"NO_GROUPS_FOUND": "找不到群組",
"CATCHUP_AVAILABLE": "Catchup 可用",
"CATCHUP_AVAILABLE_DAYS": "Catchup 可用 — {{days}} 天",
"TRY_DIFFERENT_SEARCH": "請嘗試其他搜尋詞",
"DETAILS_DIALOG": {
"TITLE": "頻道詳細資訊",