Files
iptvnator/libs/ui
4grayandClaude Fable 5.1 e6df866787 style(ui): every remaining dialog onto the shared dialog shell (#1957)
* style(ui): every remaining dialog onto the shared dialog shell

Sixteen dialogs move onto app-dialog-shell, so every dialog shares one
frame: the header with its icon tile, heading, subtitle and close button,
the body, and a footer with the dismiss first and the main action last.
Settings unsaved changes and delete all, the server migration prompt, the
external player notice, source cleanup, the group, category, lock and EPG
mapping pickers, playlist details, both account info dialogs, channel
details, downloaded episodes, episode info, the trailer, release notes and
the parental lock PIN.

A hero dialog keeps its stats band as the body's first block, edge to
edge, with its title in the shell's header and its status pills in the
header's end slot; a media dialog does the same with its frame or still.
Widths come from dialogSize() at every opener; the account dialogs and the
trailer keep their wider explicit widths. The command palette, the
programme dialog and the EPG import panel stay as they are, by design.

Specs that pinned the old literal widths at the openers now expect the
preset values; the delete-all spec counts the footer's buttons, since the
shell adds its header close.

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

* fix(ui): let a picker's list own the scrolling; keep cleanup's lock on close

A child of the dialog shell's body cannot size itself from the body's
height: a flex item's height is indefinite for percentages, so the list
wrappers' height: 100% never resolved. With eighty groups the wrapper grew
to its content, the whole body scrolled and the search box and bulk actions
scrolled away. The shell gains bodyLayout="column", which lays the body out
as a flex column; the three list pickers set it, their wrapper flexes to
the height left under the cap and only the list scrolls. An Electron E2E
imports eighty groups and checks that the body holds still, the list
scrolls and the search box stays in view; it fails without the fix.

The source cleanup dialog hides the shell's header close while it deletes:
mat-dialog-close ignores disableClose, so the header close would have
ended the batch and hidden its results. Stop stays the one way out.

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

* fix(ui): close the shell with no result; hide its close while a save runs

A bare mat-dialog-close attribute closes with an empty string, not with
undefined as Escape and the backdrop do. The parental lock services take
any string for an entered PIN, so the shell's header close would have
opened the lock on a bare dismissal, and the groups view would have taken
the empty string for a saved result. The header close now binds undefined.
The shell's spec asserts it, and the PIN dialog's spec that its header
close cancels.

The Xtream category and Stalker lock pickers hide the header close while
they save: mat-dialog-close ignores disableClose, and a dismissal mid-save
would have skipped the caller's reload while the writes still finished.

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

* fix(ui): wrap an unbreakable heading in the dialog shell

A shell heading often carries provider text: an episode's file name, a
channel name with no spaces. Such a string has no break opportunity, and
the episode title lost the overflow-wrap it had before the shell, so it
ran under the header's close button. The shell's heading and subtitle now
wrap anywhere. An Electron E2E opens channel details for an underscore-only
channel name in a narrow window and checks the title wraps and stays clear
of the close button; it fails without the rule.

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

* refactor(ui): one opener for the channel details dialog

Five channel lists opened the channel details dialog with the same size
preset repeated at each site. The dialog now owns its settings in a static
open(dialog, channel), as the EPG mapping and PIN dialogs do, so a later
size change cannot miss a caller.

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

* fix(ui): keep the hero bands' grid stretched in a narrow window

Removing the padding rules the shell made redundant left the hero selector
grouped with the status pills' left-alignment rule in both hero
stylesheets. On a grid, justify-content: flex-start stops the implicit
column from stretching, so under 720px the account stats shrank to their
content, 157px in a 355px band. Only the status pills re-align now. An
Electron E2E opens the account dialog in a narrow window and checks the
stats fill the band; it fails without the fix.

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

* refactor(settings): one opener for the release notes dialog

The notification card and the settings facade opened the release notes
dialog with the same size, autofocus and restore settings repeated at each
site. The dialog now owns them in a static open(dialog, data); a caller
picks only which release to show.

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

* test(ui): measure the hero band against the body's client width

The narrow-window hero test compared the band to the body's bounding
width, which on Linux includes the 15px scrollbar that macOS overlays, so
it failed on the ubuntu runners while passing on a Mac. The client width
leaves the scrollbar out on both.

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

* test(ui): keep the fraction when measuring the hero band's body

clientWidth is an integer; against the band's fractional bounding width it
left a 1.4px difference on a Mac. The body's bounding width minus its
integer scrollbar width keeps the fraction and still leaves out the
classic scrollbar the CI runners draw.

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

* fix(ui): keep the dialog shell's header close reachable when the dialog scrolls

Under 600px of height the shell let Material's surface scroll every
dialog whole, so the header close scrolled away; a dialog without a
footer (account info, downloaded episodes, keyboard shortcuts) then had
no in-dialog dismissal left in view. Such a dialog now keeps its body as
the scroll owner, with the header in place; the cap still comes off for
a dialog with a footer, whose stacked actions would squeeze the body.

An opener's `maxHeight` tighter than the shell's own cap (the account
dialogs' 90vh) also left the surface scrolling: the dialog component
between the surface and the shell is a block that never shrinks below
its content. Those ancestors are now shrinkable flex columns, so the
shell sizes from the surface and only the body scrolls.

The dialog-shell E2E opens the account dialog in a 520px-tall window,
scrolls both candidate owners and checks that the body took the scroll
and the close button stayed inside the surface; it fails without either
rule.

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

* fix(ui): hide the PIN dialog's header close while a verification is pending

The dialog disables its field, Cancel and Submit while the caller's
`verify` runs, but the shell's header close stayed enabled: a dismissal
then handed the caller a cancel, and an accepted PIN could no longer be
delivered. The close now follows Cancel, as the category and lock
pickers' does while they save. The spec holds a verification open and
checks that the close is gone and the accepted PIN still arrives.

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

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-16 15:24:25 +02:00
..