Commit Graph

57 Commits

Author SHA1 Message Date
Arkadiusz Fal
d8722e6150 Remove overlay pattern from tvOS search results to fix focus clipping
The backgroundStyle.ignoresSafeArea().overlay(ScrollView) pattern
clips the tvOS focus effect at the overlay boundary. On tvOS, render
the ScrollView directly so focus highlights can extend naturally.
2026-04-18 20:38:01 +02:00
Arkadiusz Fal
885c478857 Increase top spacing for tvOS focus effect on first content row
Add padding above the content area so the tvOS focus highlight on the
first row isn't clipped by the search header above it.
2026-04-18 20:38:01 +02:00
Arkadiusz Fal
c3a2f7a965 Add bottom padding to tvOS search header for focus effect clearance 2026-04-18 20:38:01 +02:00
Arkadiusz Fal
5417374275 Consolidate tvOS search header: search, type, filters, view options
Reorganize the tvOS search UI into a single header row with search
field, type filter menu, combined filters menu (sort/date/duration
with reset), and view options button. Removes the separate filter
strip between search and results on tvOS.
2026-04-18 20:38:01 +02:00
Arkadiusz Fal
84db5d0c42 Use List instead of Form for View Options on tvOS
Form inside a sheet causes clipped rows and invisible text on focused
items due to white-on-white rendering. Use a plain List on tvOS which
handles the focus styling correctly.
2026-04-18 20:38:01 +02:00
Arkadiusz Fal
310869fad8 Add horizontal padding to View Options sheet on tvOS
Prevents form rows from being cut off at the left and right edges
of the narrow tvOS sheet.
2026-04-18 20:38:01 +02:00
Arkadiusz Fal
58c3bdc0b6 Wrap View Options sheet in NavigationStack on tvOS for picker labels
The .pickerStyle(.menu) hid labels. Instead, wrap the Form in a
NavigationStack on tvOS so the default navigation picker style works
and shows both labels and values.
2026-04-18 20:38:01 +02:00
Arkadiusz Fal
338127c692 Fix disabled pickers in View Options sheet on tvOS
Use .pickerStyle(.menu) for Row Size, Columns, and Channel Strip
pickers on tvOS so they work inside a sheet without NavigationStack.
2026-04-18 20:38:01 +02:00
Arkadiusz Fal
d62ba1e143 Hide list row dividers and card clipping on tvOS
Dividers inside rows conflict with the tvOS focus highlight effect.
Remove dividers and the inset card background/clipShape on tvOS so
the focus effect renders cleanly without visual artifacts.
2026-04-18 20:38:01 +02:00
Arkadiusz Fal
3c7581de1a Replace search content type segmented picker with Menu on tvOS
Unifies the filter strip on tvOS so all filters (sort, date, duration,
content type) use the same inline Menu style instead of mixing menus
with a segmented picker.
2026-04-18 20:38:01 +02:00
Arkadiusz Fal
831773a609 Replace search filters sheet with inline menus on tvOS
The filters sheet is too small and awkward on tvOS. Replace the filter
button with inline Menu pickers for Sort By, Upload Date, and Duration
directly in the filter strip. Applied to both SearchView and
InstanceBrowseView.
2026-04-18 20:38:01 +02:00
Arkadiusz Fal
bcb0864fca Fix tvOS search view: replace searchable with inline TextField, fix clipped focus
Use inline TextField with focusSection instead of .searchable() on tvOS
to prevent keyboard/navigation title overlap. Remove clipShape on recent
search items so tvOS focus effect is not cut off.
2026-04-18 20:38:01 +02:00
Arkadiusz Fal
bbeb38ecf0 Hide link action, clipboard, and handoff settings on tvOS
These features are not available on Apple TV: clipboard monitoring,
default link action (no tap/share), and Handoff continuity.
2026-04-18 20:38:01 +02:00
Arkadiusz Fal
5ae1fc3f29 Fix tvOS instance browse view overlapping search and navigation UI
Use inline TextField with focusSection instead of .searchable() and
.navigationTitle() on tvOS, matching the pattern in HistoryListView.
2026-04-18 20:38:01 +02:00
Arkadiusz Fal
4b245ec176 Improve tvOS settings layout: use navigation instead of sheets, fix focus clipping
- Replace sheets with navigationDestination for Add/Edit Source on tvOS
  (tvOS sheets have fixed size that doesn't fit the content)
- Fix focused cell clipping by replacing TVSettingsContainer's frame-based
  layout with safeAreaInset, matching the main settings view pattern
- Use standard List with .listStyle(.grouped) for Sources on tvOS
- Add sidebar icons and titles to TVSettingsContainer for all settings
  subviews, utilizing the left column space
- Remove redundant large navigation titles on tvOS (shown in sidebar)
- Move Edit Source Save button from toolbar into form above Delete button
  for better tvOS focus navigation
2026-04-18 20:38:01 +02:00
Arkadiusz Fal
eefd49f743 Fix three basic-auth regressions surfaced by end-to-end testing
- InstanceDetector: a single 401 from one probe was over-eagerly concluded
  as "credentials invalid" / "credentials required". On instances behind a
  reverse proxy where one probe path (e.g. Yattee Server's /info) hits a
  same-origin redirect, iOS URLSession strips the Authorization header on
  the redirect and the request 401s even with valid credentials. Track 401s
  across all probes and only conclude basicAuthRequired/basicAuthInvalid
  when no probe matched and at least one returned 401.

- InstanceLoginView: the Invidious/Piped login flow constructed an API
  client backed by the shared appEnvironment.httpClient, which has no
  per-instance basic-auth headers. For instances behind a reverse proxy,
  the login POST 401d before reaching the upstream login endpoint. Build a
  per-instance HTTPClient with the basic-auth Authorization header baked in
  via setDefaultHeaders, mirroring ContentService.httpClientWithBasicAuth.

- InvidiousAPI.login: the login function constructs its own URLSession (to
  capture Set-Cookie via a redirect-blocking delegate), so it never
  inherits headers from the injected httpClient. Add an optional
  extraHeaders parameter and have InstanceLoginView pass the basic-auth
  header through when present. PipedAPI.login uses httpClient.fetch and
  inherits defaultHeaders correctly, so no change is needed there.
2026-04-18 20:38:00 +02:00
Arkadiusz Fal
3dd4073db7 Allow HTTP Basic Auth credentials for any remote-server instance type
EditSourceView now exposes the basic-auth username/password fields for every
instance type (Invidious, Piped, PeerTube, Yattee Server), keeping the
existing required-credentials UI for Yattee Server and adding an optional
section for the others. Credentials are loaded and persisted via
BasicAuthCredentialsManager regardless of type, and clearing both fields
deletes stored credentials for non-Yattee types.

AddRemoteServerView gains a new basicAuthRequired UI state: when instance
detection hits a 401 (the entire instance is behind a reverse proxy), the
view reveals username/password fields and a Retry Detection button. The
retry calls the detector with the credentials injected as an Authorization
header; on success the form transitions into the normal detected state with
the credentials pre-populated. A repeat 401 shows an inline "invalid
credentials" message instead of restarting the flow. For non-Yattee types,
any credentials entered during the flow are persisted alongside the new
instance.
2026-04-18 20:38:00 +02:00
Arkadiusz Fal
63f1cb1f25 Inject basic auth via per-instance HTTPClient default headers
Replace the YatteeServerAPI setAuthHeader/buildHeaders pattern (which was
race-prone on the shared actor across multiple instances) with a generic
mechanism: HTTPClient now supports a defaultHeaders dictionary applied to
every request, and ContentService builds a per-instance HTTPClient with the
basic-auth Authorization header baked in whenever credentials are configured.

The same code path now works uniformly for Invidious, Piped, PeerTube, and
Yattee Server, so any instance sitting behind a reverse proxy that requires
HTTP Basic Auth can be authenticated regardless of backend type. Cached
default API actors are still reused when no basic-auth header is needed.
2026-04-18 20:38:00 +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
240cf23693 Fix uneven shortcut card heights on tvOS home screen
Always reserve space for the subtitle line so cards with and without
subtitles have consistent heights in the grid.
2026-04-18 20:38:00 +02:00
Arkadiusz Fal
d6d15df105 Deduplicate time formatting and clean up unused code
Extract shared TimeInterval.formattedAsTimestamp replacing 8 identical
formatTime/formattedTime implementations across player views. Remove
unused currentTime parameter from GestureSeekPreviewView. Consolidate
duplicated geometry math in MacOSControlBar into seekPreviewPosition().
2026-04-18 20:38:00 +02:00
Arkadiusz Fal
9b734f49ad Add separate glass capsule for chapter title above seek preview
Extract chapter title from inside the storyboard preview into a
standalone ChapterCapsuleView with its own glass capsule background.
The capsule follows the seek position horizontally but independently
clamps to screen edges using alignmentGuide, allowing it to be wider
than the storyboard thumbnail without going offscreen.
2026-04-18 20:38:00 +02:00
Arkadiusz Fal
4e8959d2df Fix missing leading padding on instance content section headers 2026-04-18 20:38:00 +02:00
Arkadiusz Fal
f3061763da Show seek time preview when no storyboards available
Display a floating time pill above the seek bar during dragging
(iOS) and dragging/hovering (macOS) when video has no storyboard
thumbnails. Includes chapter name when available.
2026-04-18 20:38:00 +02:00
Arkadiusz Fal
a7e5ebb068 Fix 5 TestFlight crash types from builds 250-254
- Fix BGTaskScheduler assertion crash on Mac Catalyst by guarding all
  iOS background task APIs with isMacCatalystApp check
- Fix iPad popover crash in UIPopoverPresentationController by adding
  .presentationCompactAdaptation(.sheet) to all 27 confirmationDialogs
- Fix SwiftData assertion crash when accessing deleted Bookmark model
  properties during SwiftUI hit testing in BookmarkRowView
- Fix UICollectionView invalid item count crash on queue swipe-to-delete
  by using ID-based removal with withAnimation instead of stale index
- Fix Range crash in storyboard download when storyboardCount is zero
2026-04-18 20:38:00 +02:00
Arkadiusz Fal
8e5947c558 Fix HTTP basic auth credentials being stripped from instance URLs
Preserve user:pass credentials in instance URLs so Invidious instances
behind nginx reverse proxies with HTTP basic auth work correctly (#926).
Add displayURL property to mask credentials in the UI.
2026-04-18 20:38:00 +02:00
Arkadiusz Fal
4edb012181 Hide theme and accent color settings on tvOS
These settings don't work well on Apple TV, so exclude the
ThemeSection, AccentColorSection, and the .preferredColorScheme/.tint
modifiers from tvOS builds.
2026-04-18 20:38:00 +02:00
Arkadiusz Fal
f8da242968 Fix ContentUnavailableView centering on Apple TV
On tvOS, ContentUnavailableView inside a Group doesn't expand to fill
available space — it sizes to content and aligns top-leading. Add
.frame(maxWidth: .infinity, maxHeight: .infinity) to all instances
so they center correctly in their parent containers.
2026-04-18 20:38:00 +02:00
Arkadiusz Fal
59ccef950b Fix HomeView data staleness on new watch entries, tab switches, and settings dismissal
Post watchHistoryDidChange notification when a new watch entry is inserted
during local playback progress updates (but not on every progress tick).
Reload Home data when switching back to the Home tab and when the Customize
Home sheet is dismissed.
2026-04-18 20:38:00 +02:00
Arkadiusz Fal
acb6fb284a Fix Home view showing zero counts after returning from background
onAppear only fires once when the view first appears, not on foreground
return. Add scenePhase observer to reload data when the app becomes active.
2026-04-18 20:38:00 +02:00
Arkadiusz Fal
8c24b12b9a Migrate localization keys to dotted format
Remove 32 non-dotted keys (16 unused format specifiers, 16 word keys)
and replace with properly namespaced dotted keys following the existing
convention (common.*, player.*, search.*).
2026-04-18 20:38:00 +02:00
Arkadiusz Fal
64193911c7 Show toolbar buttons and tab picker during channel loading
Display the view options button, channel menu, and content type tabs
immediately when the cached header is shown, instead of waiting for
the full channel data to load. The spinner now appears only in the
content area below the tabs.
2026-04-18 20:38:00 +02:00
Arkadiusz Fal
6298b38cba Add video proxy support with live toggle for Invidious/Piped instances
Adds a "Proxy videos" toggle in instance settings that routes video
streams through the instance instead of connecting directly to YouTube
CDN. Includes auto-detection of 403 blocks and live re-application of
proxy settings without requiring app restart or video reload.
2026-04-18 20:38:00 +02:00
Arkadiusz Fal
2e37873a12 Remove duplicate navigation titles on tvOS
The sidebarAdaptable TabView already shows tab names in the sidebar
pill, so the large .navigationTitle() was redundant on tvOS.
2026-04-18 20:38:00 +02:00
Arkadiusz Fal
013514adc3 Fix tvOS onboarding background transparency and button styling
Add opaque black background to onboarding on tvOS to prevent Home
screen content from leaking through the fullScreenCover. Replace
toolbar Skip button with plain overlay button to avoid blurred
material style, and add tvOS card button style with default focus
on Continue button.
2026-04-18 20:38:00 +02:00
Arkadiusz Fal
e6834b6eff Add DEV badge on iCloud settings for debug builds
Shows an orange "DEV" capsule next to the iCloud row in Settings and a
development environment notice at the top of iCloud settings, helping
distinguish CloudKit dev environment from production during development.
2026-04-18 20:37:35 +02:00
Arkadiusz Fal
e38e4cca3a Fix feed channel filter avatars showing placeholders instead of images
The filter strip was passing the Invidious instance URL as serverURL to
AvatarURLBuilder, which built a Yattee Server-style /avatar/ path that
doesn't exist on Invidious. Now passes the actual Yattee Server URL
(matching SubscriptionsView pattern) and enriches channels from
CachedChannelData as a fallback when the API doesn't return thumbnails.
2026-04-18 20:37:35 +02:00
Arkadiusz Fal
7cea57c343 Update media browser view options sheet layout 2026-04-18 20:37:25 +02:00
Arkadiusz Fal
d045a64b63 Persist media browser view options per source
Save sort order, sort direction, and show-only-playable filter to
UserDefaults keyed by source ID so preferences survive navigation.
2026-04-18 20:37:25 +02:00
Arkadiusz Fal
7abd3a86fc Move close video button from toolbar into now playing card in RemoteControlView 2026-04-18 20:37:25 +02:00
Arkadiusz Fal
5c82c37339 Add Enable All / Disable All menu to channel notifications settings 2026-04-18 20:37:25 +02:00
Arkadiusz Fal
e4d275ad42 Show video thumbnail in mini player during PiP
When PiP is active, the MPV render view shows a black frame since
rendering goes to the PiP sample buffer layer. Overlay the video
thumbnail (preferring DeArrow) on top to cover the black area,
fading it in/out smoothly when PiP starts/stops.
2026-04-18 20:37:25 +02:00
Arkadiusz Fal
2faae65e8b Add context menu and swipe actions to related videos in VideoInfoView 2026-04-18 20:37:25 +02:00
Arkadiusz Fal
fa0536549a Fix subscriber count layout shift in VideoInfoView channel row 2026-04-18 20:37:25 +02:00
Arkadiusz Fal
ef3cddefeb Persist author cache to disk for instant channel info across restarts
Back the in-memory authorCache with a JSON file in ~/Library/Caches/AuthorCache/.
Disk is lazy-loaded on first lookup and saved asynchronously on each cache update.
Capped at 500 entries to prevent unbounded growth.

- Cache author data from video detail API responses (PlayerService, VideoInfoView)
- Replace ChannelView's private CachedChannelHeader with shared CachedChannelData
- Enrich author with cached avatar/subscriber count in VideoChannelRow, TVDetailsPanel, VideoInfoView
2026-04-18 20:37:25 +02:00
Arkadiusz Fal
e3606dbb3a Fix Feed tab flashing ContentUnavailableView on initial load
When a cancelled load task fell through to `isLoading = false`, it
created a 1-frame gap where the empty view rendered before the
replacement task set `isLoading` back to `true`. Return early on
cancellation so the surviving task controls loading state.
2026-04-18 20:37:25 +02:00
Arkadiusz Fal
02de3d0bd5 Fix blurred background gradient not using DeArrow thumbnail 2026-04-18 20:37:25 +02:00
Arkadiusz Fal
41c11d8839 Fix playlist rows in ChannelView not tappable in empty space 2026-04-18 20:37:25 +02:00
Arkadiusz Fal
aaf53ef9d1 Fix lock screen always showing 10s seek regardless of system controls setting 2026-04-18 20:37:25 +02:00
Arkadiusz Fal
f010650e5e Remove excessive logging 2026-04-18 20:37:25 +02:00