206 Commits

Author SHA1 Message Date
Arkadiusz Fal
14912f0203 Configure comments from their row in details panel settings
The separate comments group (pill mode, author avatars) is gone: comments
are a row in the pages/sections list whose editor holds both options.
Inline-sections hosts list comments as a locked pill row at the bottom;
a foldable iPhone in the corner layout lists real pages, including
comments and queue in the side column.
2026-10-20 22:26:21 +02:00
Arkadiusz Fal
ef372b65d9 Keep Settings in the tvOS sidebar (#986)
tvOS has no other route to Settings, so unchecking it in Sidebar settings
locked users out. Treat Settings as a required sidebar item on tvOS; an
already-stored hidden value is ignored because required items bypass the
visibility map.
2026-10-19 21:43:46 +02:00
Arkadiusz Fal
c19be0a0ef Give the empty tvOS import screens a focusable Done button
With nothing to import, the playlists and subscriptions import screens
had no focusable content; only the container's toolbar Done, which is
not a dependable focus target on tvOS.
2026-10-18 23:15:16 +02:00
Arkadiusz Fal
f393d2b9cc Give the tvOS network share discovery sheet a focusable Cancel
The toolbar Cancel is iOS/macOS only, so while scanning with no shares
found yet (and when discovery is unavailable) the tvOS sheet had nothing
the remote could focus.
2026-10-17 15:23:00 +02:00
Arkadiusz Fal
eec39445b4 Give the empty tvOS translators screen a focusable Done button
If the bundled translator list fails to load the screen is a bare
ContentUnavailableView, leaving the tvOS remote nothing to focus.
2026-10-17 08:59:14 +02:00
Arkadiusz Fal
34cec578ad Show an empty contributors list as a placeholder with Retry
A successful load with no contributors, and the first frame before the
load started, rendered an empty form with nothing focusable, stranding
the tvOS remote.
2026-10-17 07:01:21 +02:00
Arkadiusz Fal
4fe7cceda5 Give the empty tvOS PeerTube instance browser a Retry button
When the directory returned no instances without an error, the tvOS
search header was hidden and the no-results state had nothing focusable.
2026-10-16 23:59:30 +02:00
Arkadiusz Fal
d5b5b3262d Give the empty tvOS legacy import screen a focusable Done button
The toolbar Done is iOS/macOS only, so after the last legacy account or
source was imported or removed the tvOS screen had nothing focusable and
the remote was stuck.
2026-10-15 23:57:50 +02:00
Arkadiusz Fal
164f828098 Give the empty tvOS Accounts screen a focusable Open Sources button
With no accounts the screen showed only a ContentUnavailableView, so the
focus engine had nothing to land on and the remote could not reach the
sidebar again; the app had to be force-quit. Sources is also where an
account is signed in.
2026-10-15 23:51:07 +02:00
Arkadiusz Fal
4a9a92d140 Add a Currently Playing toggle to the queue panel page
Below Previously Played in the queue page settings; off by default, so
the queue page lists history and up next without the playing video.
With it off the page opens scrolled to Up Next.
2026-10-12 19:45:02 +02:00
Arkadiusz Fal
6c7c0772fd Show the Foldable playback settings on hinged devices
The section carried its own hinge observer but rendered nothing until a
hinge was reported, so the observer never attached and the section never
appeared. Observe the hinge on the always-present form instead.
2026-10-11 23:57:38 +02:00
Arkadiusz Fal
6e8835237d Add a Navigation setting to keep the tab bar on large screens
iPad and iPhone Duo users can pick Tab Bar instead of Automatic to opt
out of the sidebar layout. Switching rebuilds the navigation Settings
lives in, so the change asks for confirmation and lands on Home first.
2026-10-11 21:28:51 +02:00
Arkadiusz Fal
82236967b7 Show player toasts and drop the unused instance status
PlayerService's toast manager was never set, so stream refresh, missing
download and skip-to-next toasts were silently dropped. Wire it up in
AppEnvironment.

InstancesManager's per-instance status was never written since the v2
rewrite; account statuses already cover rejected and missing credentials
in the sources list, so remove it along with its unreachable row branch.
2026-10-08 23:59:40 +02:00
Arkadiusz Fal
4770bbe3b9 Remove dead code found by Periphery on all platforms
Delete declarations that Periphery reports unused on every platform that
compiles them (iOS, macOS, tvOS), including nine views used only by their
own previews. Platform-gated code still used on another platform, device-
only MPV render paths, migration models, CloudKit record names, App
Intents metadata and unused parameters are kept.
2026-10-08 23:57:56 +02:00
Arkadiusz Fal
5ae07574cb Add URL scheme actions: play, queue, download, bookmark, subscribe, player controls
yattee://play|play-next|queue|download|bookmark|subscribe|unsubscribe?url={link}
and yattee://player/play|pause|toggle|next|previous|close|seek|rate run through
one LinkActionPerformer that reports a LinkActionResult, ready for
x-callback-url. An unencoded url= keeps its own query; only the action's own
parameters end it.

Actions that change saved state ask first through a confirmation sheet
presented by the top-most sheet host, unless the new 'Run Link Actions
Without Asking' setting is on. Download skips the question when the quality
picker will show anyway. Player commands leave sheets and the player alone.
2026-10-05 23:58:43 +02:00
Arkadiusz Fal
1bb78d32bf Remove keychain provenance and identity scope simulator debug tools
Both were DEBUG-only Developer settings entries used while building
the accounts revamp and are no longer needed. The simulator's
account-sync suspension barrier in AccountSyncCoordinator existed only
to keep invented scopes away from the real zone, so it goes with it.
2026-10-05 09:01:59 +02:00
Arkadiusz Fal
3e561cc3b5 Present error details and Open Link through the shared sheet host
Error details were declared in the video info view and the expanded
player, and Open Link three times: at the app root for deep links and
for the File menu command, and on Home. All of them are now AppSheets;
the deep link and menu requests go through the global request, so a
deep link that arrives while the player is expanded no longer opens the
sheet behind it.

The four sign-in modals that were a full-screen cover on tvOS and a
sheet elsewhere, each written out twice, use a platformSheet helper.
2026-10-04 21:04:19 +02:00
Arkadiusz Fal
c0495f3174 Show the sidebar layout on the iPhone Duo inner screen
The sidebar layout was gated on iPad idiom. It now appears wherever there
is room for it: regular width and regular height, or an iPad with
regular width (a short Stage Manager window keeps it). That covers the
Duo inner screen in both orientations, while large iPhones in landscape
and the Duo outer screen keep the tab bar. The subscriptions feed's
channel sidebar follows the same rule, and Sidebar settings are offered
on devices with a hinge.

SwiftUI's sidebarAdaptable TabView never shows a sidebar on iPhone
idiom, so the iOS sidebar layout now uses the NavigationSplitView with a
list sidebar that macOS already used, on iPad as well. The sidebar
layout shows the floating mini player instead of the tab bar accessory.
2026-10-03 23:26:15 +02:00
Arkadiusz Fal
86ff0d6a9e Prefer the avfoundation audio output on iOS and macOS
AVSampleBufferAudioRenderer is the system media path, so it gets Spatial
Audio / Spatialize Stereo and head tracking, which audiounit and coreaudio
output never do. iOS now uses avfoundation,audiounit like tvOS, and all
macOS versions use avfoundation,coreaudio (previously only macOS 27+).
2026-10-03 11:33:48 +02:00
Arkadiusz Fal
8252dc0ea4 Return the tvOS details panel to the fixed Info/Comments tabs
Drop the preset-driven page list on tvOS (related, chapters, queue pages
and the Player Panels settings screen) and restore the segmented
Info/Comments picker, removing the now-unused strings.
2026-10-02 23:59:56 +02:00
Arkadiusz Fal
83895a1fd9 Reflect the video below the hinge in the tabletop layout
The iPhone Duo tabletop layout mirrors every presented frame into the
lower half, blurred and fading out, like a screen standing on a glossy
table. The render view blits a quarter-resolution copy of the display
framebuffer into a ring of IOSurface-backed buffers (no Y flip, so the
surface is already mirrored) and hands it to a CALayer hosted by
MPVReflectionView; the simulator's software renderer feeds the same
layer a flipped CGImage. Off during PiP, for audio-only streams, and
via the new Playback → Foldable → "Reflection Below Video" setting.
2026-10-01 20:59:48 +02:00
Arkadiusz Fal
2fd52fff27 Support the iPhone Duo interior display in the player
The interior display refuses programmatic rotation
(UISceneErrorDomain 101: "The current windowing mode does not allow for
programmatic changes to interface orientation"), so the rotate/fullscreen
button did nothing there and the failure was swallowed.

- OrientationManager tracks `canRotateProgrammatically` (from the hinge
  state, cleared when a geometry request is refused) and is @Observable.
- The fullscreen button takes the iPad path when rotation is unavailable:
  details toggle in portrait, floating panel toggle in landscape, icon
  follows the panel state; orientation lock is hidden. The refused request
  itself falls back to the details toggle. Accelerometer-driven rotation
  requests are gated the same way.
- Corner layout gate is size-only on iOS (≥900×600 including safe areas,
  so the status bar toggling with the layout can't oscillate it); the
  layout-mode setting is exposed on foldables via a hinge presence check.
- Corner layout on iPhone always hides the status bar (the interior's
  landscape bar is a ~57pt column) and pads by the live top inset only,
  instead of the transient 82pt inset seen while unfolding.
- The player hosting controller nudges its safe area after size
  transitions so fold/unfold doesn't leave SwiftUI with stale insets.
2026-10-01 08:53:37 +02:00
Arkadiusz Fal
423c310bd4 Show every video info action in the macOS toolbar
The toolbar layout on macOS now lists Play, Download, Share, Add to Playlist
and Bookmark as separate toolbar items, with a spacer setting Play apart from
the secondary actions. The primary action picker stays iOS-only, where the
pinned action plus the ⋯ menu layout is kept, and macOS gets its own settings
footer text.

The macOS items are written out explicitly rather than with ForEach: a ForEach
inside the toolbar builder is evaluated once and never re-renders on state
changes, which left the bookmark and download icons stale.
2026-09-28 23:48:17 +02:00
Arkadiusz Fal
14fe028ece Lock the comments row in the pages editor when it sits below the video 2026-09-27 23:43:32 +02:00
Arkadiusz Fal
0bfbd47882 Replace per-page corner regions with one "Below Video" picker
The corner layout's below-video host is the portrait info panel, not a
page host: it can render only Info, plus Comments as the panel's pill on
iOS. The page editor still offered "Below Video" for every page, so
assigning Related there was accepted, stored, listed as such, and then
silently rendered in the side column.

- The Layout section gains a "Below Video" picker in corner mode:
  Nothing / Info / Info and Comments (macOS offers the first two). It
  writes the info/comments regions; the per-page Location section and
  its strings are gone.
- PanelSettings.normalizedPages clamps regions to what the host can
  render (only info/comments below, comments only together with info),
  so older presets self-correct. effectiveRegion(for:) resolves the
  platform-specific placement and is used by both the pages list labels
  and CornerPlayerLayout, replacing its own region checks.
- The layout schematic drops the below-video block for "Nothing"; the
  corner-mode footer explains the constraint.
- Tests cover the picker round-trip and the clamping.
2026-09-27 20:05:20 +02:00
Arkadiusz Fal
7f74b50e94 Make the player pill an on/off setting on iPad, drop the dead wide-layout pill overlay
On iPad both orientations show the video next to a panel, the corner
layout hosts the portrait panel in landscape, and Split View windows make
"portrait" mean "narrow", so the portrait/landscape visibility split never
matched what the user saw. PillVisibility now treats any mode except Never
as visible on iPad, and the pill editor shows a Show pill toggle there
(writes Both/Never, reads synced orientation modes as on). iPhone keeps
the four-way picker.

ExpandedPlayerSheet's bottomPillsOverlay was unreferenced; the floating
panel renders its own pill row.
2026-09-27 16:36:42 +02:00
Arkadiusz Fal
1370f68c37 Rework details panel settings: pinned info, per-orientation visibility, section defaults
Pages list
- Info is pinned first and always enabled in every layout: normalized
  pages force it to the front and enabled (older presets self-correct),
  disabling it is a no-op, and any move that would displace it snaps
  back. The iOS/macOS list renders it outside the reorderable ForEach
  (no drag handle, nothing drops above it) and the editors hide its
  enabled toggle; tvOS also hides its move buttons. The "at least one
  page must stay enabled" guard and its strings are gone since Info
  always counts.
- iPhone never renders queue or comments as pages, so its Sections list
  hides them (PanelSettings.hiddenSettingsPageTypes). Reordering goes
  through moveVisiblePages, which keeps hidden entries in their stored
  slots. Comments get their own group on the Details Panel screen
  (pill mode + avatars) and the overlay hosts pass the avatars flag.

Default visibility
- "When Player Opens" is now configured per orientation
  (portraitDefaultVisibility / landscapeDefaultVisibility). The legacy
  single value is still decoded and seeds both until set individually;
  presets that never set it default to portrait Visible, landscape
  Hidden. macOS shows one picker (no portrait layout).
- "Remember Last" no longer leaks across orientations: separate
  remembered flags, written by the portrait toggles and by the wide and
  corner layouts respectively, with the old shared flag read once as a
  fallback. The corner layout seeded from the portrait resolution
  before; it now uses landscape.

Section options (iOS inline-sections hosts)
- Chapters and Related editors gain "Expanded by Default" (on by
  default). The Info editor gains a Description group with "Expanded by
  Default" (off) and a "Collapsed Lines" stepper (1–10, default 3).
  Applied when the panel appears and on each video change.
- Expanding a collapsed section scrolls its header to the top of the
  panel: PanelPageScrollView can hand its scroll proxy to page content
  and each inline section is wrapped in one anchored container.
- The portrait panel's bottom fade sized its touch blocker from a stale
  "expanded comments pill" answer that ignored collapse on scroll, so a
  collapsed section header (the last item) sat under it and could not
  be tapped. The predicate now tracks the pill's actual collapse state.
2026-09-26 23:50:30 +02:00
Arkadiusz Fal
4210b0ab05 Simplify the wide-layout details panel: floating-only on iPhone, side as a preset setting
iPhone landscape now uses the floating panel only, always on the right;
the pin and side-toggle buttons on the grabber are gone and the pinned
setting resolves to false on phone.

iPad and macOS default to the pinned side-by-side layout, keep the pin
button to switch to floating, and pick the panel side in the preset's
panel settings instead of an on-screen arrow. The pinned state persists
as a layout preference: closing the player or the hidden default
visibility no longer resets it.

Removes PanelAlignmentButton, the global floatingDetailsPanelSide setting
and its key, FloatingPanelSide.opposite, and the legacy
wideLayoutPanelAlignment preset field.
2026-09-26 22:48:11 +02:00
Arkadiusz Fal
a81e618e74 Configure details panel sections on iPhone and honor their order
iPhone has no page switcher: the portrait panel already rendered one info
page with chapters and related videos as collapsible inline sections. The
landscape floating panel now renders the same panel (no page bar, comments
stay on the pill/overlay), and the settings screen calls the list
"Sections" there, with the page bar labels toggle hidden.

The inline sections were hardcoded to chapters then related and ignored
the configured order, enablement, and thumbnail toggles. The info page now
receives the enabled section pages from PanelSettings.inlineSections(in:)
and renders them in list order with their own settings.
2026-09-25 23:54:27 +02:00
Arkadiusz Fal
f6ba35c1f5 Remove the tracks details panel page
The quality selector sheet already covers quality, audio, subtitles and
rate, so the embedded tracks page duplicated it. Drop the page type, its
per-page settings, the editor toggles, and the visibleSections plumbing
in QualitySelectorView.
2026-09-25 20:26:09 +02:00
Arkadiusz Fal
e7458ba629 Move comments pill mode into the comments page settings
The pill mode now lives on CommentsPageSettings and is edited in the
comments page editor instead of a standalone settings section. The
legacy value on PlayerPillSettings is kept for decoding old presets
and migrated by effectivePanelSettings. Comments are loaded when
either the comments page is enabled or the pill is not disabled.
2026-09-23 22:45:38 +02:00
Arkadiusz Fal
c289e7576e Add per-page element customization and panel settings polish
Phase 5 of the player panels redesign:
- Per-page element toggles now rendered and editable for every page:
  comments (author avatars), related (thumbnails), chapters (thumbnails),
  queue (previously played section), tracks (video/audio/subtitles/speed
  sections)
- Page bar labels toggle (icons-only bar shows the selected page's name)
- Layout mode schematic diagram in the details panel settings
- NEW badge machinery for future page types (versionAdded on PanelPageType)
- Typed per-page settings accessors on PanelPageConfiguration and VM update
  helpers for each page kind
- Unit tests for per-page settings round-trip and accessor fallbacks

The standalone quality selector sheet is unaffected: section gating defaults
to everything visible and only the embedded tracks page passes preset
settings through.
2026-09-22 09:37:10 +02:00
Arkadiusz Fal
052cb76702 Add preset-driven details panel pages on tvOS
TVDetailsPanel now renders the active tvOS preset's panel pages (info,
comments, related, chapters, queue; tracks stays with the quality panel)
with runtime hiding of empty pages, a segmented picker for up to four
pages and a focusable capsule row above that, and Info element toggles
honored. Comments unify on the PlayerState loader; the tvOS queue list
is extracted from QueueManagementSheet into TVQueueListView and reused
as the queue page. New related/chapters focus-based pages: selecting a
related video plays it and dismisses the panel, chapters seek and keep
the panel open.

New minimal Settings > Player Panels screen edits the active tvOS
preset via the existing service: duplicate-to-edit, page toggles with
last-page guard, Move Up/Down reordering, and Info element toggles.
2026-09-21 23:54:14 +02:00
Arkadiusz Fal
a6d989c7af Add corner player layout on iPad and macOS
Preset-selected two-region layout: video in the top-left, a resizable
side column, and an optional region below the video. Pages are assigned
to regions per preset (Location picker in the page editor); the layout
falls back to the stacked widescreen layout below 900pt width, so Split
View and narrow windows degrade automatically.

- CornerPlayerLayout hosts the shared playerAreaForWidescreen builder,
  so the MPV hosting path is identical to the stacked layout
- Layout resolver in ExpandedPlayerSheet picks corner per layout pass;
  NavigationCoordinator.isCornerLayoutActive feeds the macOS window
  manager, which drops the aspect-ratio lock and auto-fit while corner
  is active (and restores them on exit, incl. fullscreen replay and
  window re-mounts)
- Side column width persisted via new cornerPanelColumnWidth setting
  (280-560pt, video column kept >= 480pt)
- Settings: layout mode picker (iPad/macOS) with automatic-fallback
  footer, per-page region picker when corner is on, region shown in
  the pages list
2026-09-21 23:52:09 +02:00
Arkadiusz Fal
c33d125553 Add details panel preset settings UI and default visibility
Phase 2 of the player panels redesign:

- New "Details Panel" screen in Player Controls settings: page
  reorder/enable list with per-page editor (info element toggles),
  and a default panel visibility picker (hidden/visible/remember).
- PlayerControlsSettingsViewModel gains panelSettings bindings with
  the usual debounced-save flow; the last enabled page cannot be
  disabled.
- Built-in presets bumped to v9 with explicit default panelSettings.
- The preset's default visibility now drives the wide-layout panel
  on player open and on entering landscape, replacing the hard
  hidden resets; "remember" restores the new detailsPanelLastVisible
  setting recorded on user toggles. Applied once per expanded player
  session (flag on NavigationCoordinator survives re-mounts).
- WideScreenPlayerLayout picks up external visibility writes so the
  async-loaded default reaches the mounted layout.
- Unit tests for PanelSettings Codable compatibility (round-trip,
  old JSON, unknown page types/discriminators/enum values); removed
  stale PlayerInfoTab tests left from Phase 1.
2026-09-21 23:25:10 +02:00
Arkadiusz Fal
5651f8d431 Add a toolbar layout for the video info actions with a configurable primary action
Layout & Navigation gains a Video Info section on iOS/macOS: the actions
(Play, Download, Share, Add to Playlist, Bookmark) can stay as inline
button rows or move to the navigation bar, where the chosen primary
action is pinned and the rest live in an ellipsis menu. The toolbar
layout with Download pinned is the new default, since the hero thumbnail
already plays the video on tap; a one-time TipKit popover on the
thumbnail points that out. tvOS keeps the existing button layout.
2026-09-20 23:52:20 +02:00
Arkadiusz Fal
794b2b0181 Let accounts be set inactive without signing them out
An inactive account keeps its credential and syncs like a rename, but
drops out of every picker and cannot be used until activated again.
Deactivating the selected account switches to the local context as a
published choice, so other devices follow instead of falling back.
2026-09-19 23:58:24 +02:00
Arkadiusz Fal
de8ed91029 Use a scheme-adaptive background for tvOS full screen covers
tvOS full screen covers are transparent, so each one filled itself with
a hardcoded black — invisible black-on-black text under the light color
scheme (e.g. the View All Comments page). A shared
tvFullScreenCoverBackground() modifier now picks black or light gray
from the color scheme; applied to the comments cover, subscription
destination picker, instance login, edit source, iCloud progress, and
legacy accounts import covers.
2026-09-19 23:04:01 +02:00
Arkadiusz Fal
5cd8d586c6 Add build date to the About settings view 2026-09-18 23:59:29 +02:00
Arkadiusz Fal
d22abf6088 Add an option to share videos via privacy frontend URLs
When enabled (the default), share links to YouTube videos point to the
active source's web watch page instead of youtube.com. Invidious serves
its frontend at the API URL; Piped uses its configured frontend URL.
Videos the active source can't serve (PeerTube, extracted sources) and
sources without a web frontend keep their original links.

The toggle lives in Settings > Layout & Navigation > Sharing on iOS and
macOS, and is shown only when an enabled source has a web watch page.
2026-09-18 23:57:34 +02:00
Arkadiusz Fal
172d712f25 Add an optional frontend URL for Piped instances used by browser actions 2026-09-18 23:36:11 +02:00
Arkadiusz Fal
2a816bd893 Move basic auth credentials into the Security section in the instance edit form 2026-09-17 23:59:28 +02:00
Arkadiusz Fal
101880d35f Route instance subscription imports through SubscriptionService with a destination picker
ImportSubscriptionsView wrote every imported channel straight into the
local SwiftData store via dataManager.subscribe(to:), regardless of the
selected account context. Imports now go through
SubscriptionService.subscribe(to:in:) aimed at a destination the user
picks — the local store or any logged-in account that supports
subscriptions, minus the source instance's own account, the same roster
the subscribe menus offer.

The already-subscribed marks are asked per destination through a new
SubscriptionService.subscribedChannelIDs(in:) helper (cold server
destinations fetch their list once, generation-fenced like the other
reads) and reload when the destination changes. Individual adds show a
per-row spinner while the server write is in flight, alreadySubscribed
counts as success, and Add All runs serially with an added/failed tally.

Also drop the "Invidious" wording from the import empty state — the
view serves Piped sources too.
2026-09-17 23:23:56 +02:00
Arkadiusz Fal
b413648ab9 Hold the Accounts settings entry until a source can hold an account 2026-09-16 22:45:41 +02:00
Arkadiusz Fal
ded53d7962 Fold the tvOS account actions into a press-raised dialog
Each account was four focusable rows tall on tvOS — Use this account,
Sign in again, Rename and Sign out all spelled out as siblings, a lot
of clicking past on a remote. The row itself is now the one focusable
unit: pressing it raises the same actions as a confirmation dialog,
mirroring the context menu the other platforms already attach.
2026-09-14 18:28:28 +02:00
Arkadiusz Fal
69d22cdc98 Withhold every account switcher until an account exists to offer 2026-09-13 20:16:14 +02:00
Arkadiusz Fal
5136b79f49 Let the user hide the account pickers outside Settings 2026-09-13 18:56:18 +02:00
Arkadiusz Fal
b8921387dd Let the accounts screen own the switcher instead of the settings list
The main settings list carried both an Accounts row and a switcher row
beside it — two account controls at the top level, one of them opening
the screen the other belonged on. The switcher row moves to the top of
the accounts screen as a Current Account section, where the selection
it names sits directly above the checkmarked row it corresponds to.

The subscriptions-settings row and the macOS sidebar footer keep
theirs: those are contextual surfaces, not the settings list.
2026-09-12 23:58:32 +02:00
Arkadiusz Fal
3281840a8e Let the login sheet respect its edges and the account footer tell the truth
MAC2/MAC15: the macOS login form is grouped like its Edit Source parent, so
labels sit inside the sheet and the add-flow step stops clipping; footers
wrap instead of truncating.
MAC12: the account section footer consults account statuses before claiming
the user is logged in.
2026-09-11 19:36:50 +02:00
Arkadiusz Fal
e661635079 Let every menu mark the current context and a disabled source admit it
MAC1: switcher rows are Toggles on macOS so the checkmark really renders,
and the settings row names its context via LabeledContent with a tooltip.
MAC4: accessible names are words, never raw SF Symbol identifiers.
MAC14: new displayStatus(for:) surfaces instanceDisabled on account rows,
badges, and the switcher tooltip without disturbing status(for:) consumers.
MAC16: disambiguated labels guard the username branch and fall back to the
source name only when rows would still collide.
Also carries the new Localizable strings for the whole macOS fix batch.
2026-09-11 08:02:26 +02:00