33 Commits

Author SHA1 Message Date
Arkadiusz Fal
1c57a55fe1 Return to Home when the selected sidebar source is removed 2026-10-22 07:58:09 +02:00
Arkadiusz Fal
97288b4497 Keep the split view mini player on pushed pages
The detail column absorbs its NavigationStack, so the mini player inset
on the stack only reached the root page and disappeared on push. Float
it over the split view, past the sidebar, and have every page reserve
its height as bottom safe area.
2026-10-13 23:58:49 +02:00
Arkadiusz Fal
7b1a24a5b0 Morph the expanded player into the mini player on drag-to-dismiss
Releasing the dismiss drag now shrinks the player window onto its video and
flies it into the mini player's preview instead of sliding it off screen and
showing the mini player afterwards. The mini player stays mounted under the
expanded player and reports its preview frame, and the window is masked down
to the video while its root view is transformed onto that frame (with the
safe area the transform drops added back, so the content doesn't jump).

The handoff of the shared MPV view is made seamless: a freshly made player
container waits for its first layout before taking a view that is on screen
elsewhere, sizes and redraws it there, and the window hides in that same
frame. Resizing the render view draws the current frame into the recreated
framebuffer right away instead of leaving it blank until the next tick.

Falls back to the slide when no preview target is available (rotated
session, video preview hidden, different window size).
2026-10-09 23:59:51 +02:00
Arkadiusz Fal
cf8d477351 Inset the mini player into the split view's detail column
The floating overlay ignored the safe area, so the subscriptions channel
strip sat under it on the iPhone Duo inner screen and iPad.
2026-10-09 23:59:41 +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
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
b26b7d342f Keep navigation state in a router shared by both iOS layouts
The tab bar and sidebar layouts each kept their own navigation paths and
selection, so swapping between them (resizing an iPad Stage Manager
window across the size-class breakpoint) lost every pushed screen and
re-applied the startup tab.

NavigationRouter now holds the selected section, a typed stack per
section keyed by SidebarItem.id, the search text and the sidebar
manager. Both layouts select with SidebarItem and render the router's
state; navigate(to:) pushes onto it directly instead of going through
an observed pendingNavigation, so a request made before a layout
appears is not lost, and a destination pushed before startup keeps its
section. When a layout can't show the selection (a sidebar channel in
the tab bar, a section hidden by customization) it lands on the section
that can host it with that screen pushed first.

This also fixes keyboard section commands in the tab bar layout and the
coordinator's stale tab on iPad. AppTab, pendingNavigation,
selectedSidebarItem and the unused SheetDestination/path API are gone,
and the iOS 18 and 26.1 root views are merged into AdaptiveTabView.
2026-10-03 23:24:50 +02:00
Arkadiusz Fal
8a8f3a6000 Restore search field activation when selecting the search tab on iOS 27
iOS 27 changed the default TabSearchActivation so a role: .search tab no
longer focuses the search field on selection. Opt back into the iOS 26
behavior with .tabViewSearchActivation(.searchTabSelection).
2026-09-30 23:57:22 +02:00
Arkadiusz Fal
59c4f27bc7 Slim the iPad sidebar switcher pill to icon and account name 2026-09-16 18:27:17 +02:00
Arkadiusz Fal
a5ed91620f Back the iPad sidebar switcher with its own pill 2026-09-15 23:57:59 +02:00
Arkadiusz Fal
0aa79221f4 Pin the account switcher under the iPad sidebar like macOS 2026-09-15 23:56:46 +02:00
Arkadiusz Fal
82ef5267c4 Let the sidebar's channels and playlists follow the data context 2026-09-14 07:11: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
175b98097a Put the account switcher where the data is, and retire the old setting
Switching accounts was buried in Subscriptions settings behind a picker
and a confirmation dialog, and it wrote two stores that could disagree.
One shared switcher now sits in the Subscriptions and Playlists
toolbars, the macOS sidebar footer and the Settings root, and every path
goes through AppEnvironment.switchDataContext(to:) so a switch behaves
the same wherever it is made. Switching is one tap: it is reversible, so
there is nothing to confirm.

Rows come from DataContextValidator.availableContexts, name themselves
through displayName(for:), and carry a status suffix when the account is
not signed in — plus the instance host when two accounts share a name.
tvOS gets the same rows as a full-screen picker.

Subscriptions also explains itself when the selected account cannot
answer: a thin banner names the cause and says the data below is local.
This is the first consumer of the validator's unavailability, and
correctIfContextRemoved() now runs on foreground activation, where
SubscriptionAccountValidator used to auto-correct any selection it could
not immediately verify.

With the switcher reading the context directly, the legacy
subscriptionAccount setting has no readers left: the setting, its
validator, the mirror that kept it in step and the feed cache's
instance-keyed fallbacks all go. The cache invalidation the mirror also
carried stays, under its own name. AccountsManager still reads the raw
legacy key for the one-way context migration.
2026-09-03 23:59:32 +02:00
Arkadiusz Fal
5b9cd8c521 Dismiss tvOS sidebar detail pages when sidebar selection changes
tvOS's sidebarAdaptable TabView leaves the previously-pushed detail view
visible after the user picks another sidebar item, until they manually
press Menu. Broadcast a notification on tab change so any pushed
TVSidebarDetailContainer dismisses itself, and reset each tab's
NavigationPath. Also drop a redundant inner NavigationStack in the tvOS
SettingsView so subpages register on the tab's outer stack.
2026-05-08 19:35:36 +02:00
Arkadiusz Fal
3b9144cd28 Fix macOS sidebar dynamic item switching 2026-04-23 23:19:39 +02:00
Arkadiusz Fal
cda983651e Restore Settings as sidebar item on macOS
Remove the gear toolbar button that opened Settings as a sheet in the
NavigationSplitView sidebar column, and drop the macOS guard hiding
.settings from SidebarMainItem so it can be added to the sidebar and
rendered in the detail column like other items. The dedicated Settings
window (Cmd+,) is unchanged.
2026-04-23 18:00:42 +02:00
Arkadiusz Fal
cee2793399 Use NavigationSplitView on macOS with persistent sidebar Settings button
Replaces the macOS TabView(.sidebarAdaptable) root with NavigationSplitView
so the Settings gear can live in the sidebar column's toolbar (next to the
sidebar toggle) instead of only appearing in HomeView's detail toolbar.
2026-04-19 14:01:06 +02:00
Arkadiusz Fal
f60a6e3eec Fix tvOS focus trap on empty Home after fresh install
Render a focusable empty state on tvOS Home when no sections have content,
with an "Open Sources" button that switches the sidebar selection. Without
a focusable view the tvOS focus engine had no target, leaving the sidebar
unreachable after the initial iCloud alert was dismissed.

Also wire the selectedSidebarItem onChange handler into the tvOS TabView,
which was missing and prevented programmatic sidebar selection.
2026-04-18 20:38:02 +02:00
Arkadiusz Fal
13ade8aad3 Add Continue Watching toggle to tab bar settings
Exposes ContinueWatchingView as an opt-in compact tab bar item,
hidden by default. Uses a short "Continue" label since the full
"Continue Watching" string does not fit as a tab bar title.
2026-04-18 20:38:02 +02:00
Arkadiusz Fal
c0184712a9 Add Continue Watching toggle to sidebar settings
Exposes ContinueWatchingView as an opt-in main sidebar item,
hidden by default.
2026-04-18 20:38:02 +02:00
Arkadiusz Fal
4c8a3ee5ba Push video info navigation from media source browser on tvOS
handlePendingNavigation guarded the .mediaSource append with
#if os(iOS) || os(macOS), so navigating to video info from a media
source on tvOS was silently dropped. The NavigationStack binding is
already unconditional, so the append is safe on all platforms.
2026-04-18 20:38:02 +02:00
Arkadiusz Fal
a660591e8d Add Playlists entry to sidebar main navigation
Adds a toggleable "Playlists" item that opens PlaylistsListView,
mirroring the Channels → ManageChannelsView pattern.
2026-04-18 20:38:01 +02:00
Arkadiusz Fal
a3275f4cd7 Fix tvOS sidebar media source showing empty screen 2026-04-18 20:38:01 +02:00
Arkadiusz Fal
68ab994798 Drop redundant navigation titles in tvOS Open URL and Remote Control
The sidebar decoration added by TVSidebarDetailContainer already shows
the screen title, so the navigation title would duplicate it on tvOS.
2026-04-18 20:38:01 +02:00
Arkadiusz Fal
b8390577cc Rename TVSettingsContainer to TVSidebarDetailContainer
The container is now used beyond settings (Open URL and Remote Control
tabs), so the name is broadened to reflect its general role as a
tvOS sidebar-decorated detail container.
2026-04-18 20:38:01 +02:00
Arkadiusz Fal
29e8d64c35 Use settings container layout for tvOS Open URL and Remote Control
Wrap OpenLinkView and RemoteControlContentView in TVSettingsContainer on
tvOS so they get the same left sidebar with large SF Symbol icon and
title as settings detail screens, for visual consistency.
2026-04-18 20:38:01 +02:00
Arkadiusz Fal
6a45ed7d0f Show video title and channel in tvOS sidebar Now Playing 2026-04-18 20:38:01 +02:00
Arkadiusz Fal
d422bf13e5 Add Open URL and Remote Control as sidebar items
After disabling home shortcuts on tvOS, Open URL and Remote Control had
no entry point. Add them as configurable sidebar main items. Remote
Control defaults to visible on tvOS; Open URL defaults to hidden on all
platforms.
2026-04-18 20:38:01 +02:00
Arkadiusz Fal
8cd3aca96c Generalize Yattee Server credentials manager to BasicAuthCredentialsManager
Renames YatteeServerCredentialsManager → BasicAuthCredentialsManager so the
same Keychain-backed username/password storage can be reused for any instance
type that sits behind a reverse proxy requiring HTTP Basic Auth. Adds a
one-time migration that moves existing items from the legacy
'com.yattee.yatteeserver' Keychain service to 'com.yattee.basicauth',
preserving the iCloud-sync attribute. No behavior change for end users.
2026-04-18 20:38:00 +02:00
Arkadiusz Fal
11a8c79e21 Refactor views 2026-04-18 20:37:25 +02:00
Arkadiusz Fal
100df744d9 Yattee v2 rewrite 2026-04-18 20:37:24 +02:00