Improved text contrast on overlay buttons by:
- Applying foreground color directly to button labels to ensure proper override
- Using semi-transparent gray background for unfocused buttons instead of Color.secondary
- Removing accent color overrides from caption text to respect button styling
This ensures readable text in both focused (black on white) and unfocused
(white on gray) states.
Changed context menus from press-and-hold to single-press for better UX:
- Quality profile selection
- Stream quality selection
- Captions selection
- Audio track selection
Updated ControlsOverlayButton to support tap actions via new onSelect parameter.
Replaced .contextMenu modifiers with .alert for instant menu access on tvOS.
Removed hint text and unnecessary 80px padding as single-press is self-evident.
The captions context menu on tvOS was always empty because it relied on
an .onAppear callback that was never triggered. The captionsPicker view
with .onAppear was only rendered on iOS/macOS, not tvOS.
Changes:
- Access captions directly from player.currentVideo?.captions instead of
using a state variable populated via .onAppear
- Fix label logic to show "Disabled" when captions are available but not
selected, and "Not available" only when video has no captions
- Remove unused state variables and helper functions
In fullscreen playback, swipe-down and timeline seek gestures now respect a 60pt safe zone at the top of the screen, allowing the system notification center gesture to work without triggering app gestures.
Comments at the bottom of the comments view were not accessible on iOS
without entering fullscreen mode. The issue was caused by the VideoDetails
view being offset by the player height when not in fullscreen, but the
ScrollView padding didn't account for this offset.
Changes:
- Add SafeAreaModel observer for iOS platform
- Update bottom padding to dynamically account for player height offset
and safe area insets based on fullscreen state
- When not in fullscreen: padding = player height + safe area bottom + 20
- When in fullscreen: padding = max(60, safe area bottom + 20)
This ensures all comments and video details content are fully scrollable
and visible regardless of fullscreen state.
This adds a new instance setting for Invidious that filters out videos
without duration information from feeds, popular, trending, search results,
and channel pages. This can be used to hide YouTube Shorts.
The setting is labeled as "Experimental: Hide videos without duration" and
includes an explanation that it can be used to hide shorts.
Key changes:
- Added hideVideosWithoutDuration property to Instance model
- Updated InstancesBridge to serialize/deserialize the new setting
- Added UI toggle in InstanceSettings with explanatory footer text
- Implemented filtering in InvidiousAPI for:
* Popular videos
* Trending videos
* Search results
* Subscription feed
* Channel content
- Videos accessed directly by URL are not filtered
Removed auto-focus logic that was causing keyboard show/hide loop
on iPad with docked keyboard. The keyboard was repeatedly dismissing
immediately after appearing due to interaction between keyboard
notifications, focus state changes, and view updates.
Changes:
- Removed focused state and keyboard observer from SearchModel
- Removed iOS textField reference (kept macOS only)
- Removed auto-focus logic from FocusableSearchTextField on iOS
- Cleaned up unused focus-related code
The search field now works reliably when tapped manually on iPad.
Auto-focus still works on macOS where it doesn't cause issues.
Add startup cleanup to remove trending-related settings when the feature flag is disabled:
- Remove trending from visible sections
- Reset startup section to home if it was set to trending
- Remove all trending favorite items
This ensures users don't have invalid/broken settings referencing the disabled trending feature.
Change the Trending menu command to be completely hidden when the feature flag is disabled, rather than just being disabled and still visible in the UI.
Introduces a feature flag to disable the Trending section across the app. When disabled, all trending-related UI elements, navigation links, and settings are hidden.
Changes:
- Add trendingEnabled feature flag to FeatureFlags.swift (currently disabled)
- Hide Trending tab in AppTabNavigation, Sidebar, and TVNavigationView
- Remove Trending option from visible sections settings
- Remove Trending option from startup section picker
- Disable Trending menu command and keyboard shortcut
- Prevent Trending URL navigation in OpenURLHandler
- Hide Trending in FavoriteItemView navigation
Replace arrow.up.right.circle.fill icon with chart.bar.fill for the Popular section across all navigation contexts (tab bar, sidebar, and view header).
The hide shorts feature is no longer working due to API changes that prevent reliable detection of short videos. This commit introduces a feature flag system to disable the functionality while preserving the ability to easily restore it if the API issue is resolved.
Changes:
- Add FeatureFlags.swift with hideShortsEnabled flag (currently disabled)
- Hide all HideShortsButtons UI elements when flag is disabled
- Disable shorts filtering logic in ContentItemView, FavoriteItemView, and FeedModel
- Preserve hideShorts user preference for future restoration
Tab selection was being set immediately during app configuration, before
the user account had completed sign-in. This caused tabs that require
authentication (like Subscriptions and Playlists) to not be properly
selected on startup since they weren't visible yet.
Changes:
- Add notification system for account configuration completion
- Post notification after all account types finish configuration:
* Accounts with existing tokens
* Accounts requiring sign-in (after network request completes)
* Anonymous/public accounts
* Error cases (missing credentials, network failures)
- Set up observer before account configuration to ensure notification
is received
- Set tab selection only when account is fully configured
Fixed issues with thumbnails being stretched vertically and layout jumping during image loading:
- Simplified VideoCellThumbnail to always use 16:9 aspect ratio with .fill mode
- Added matching 16:9 aspect ratio to placeholder with .fill mode to prevent layout shifts
- Removed quality-based aspect ratio selection (4:3 vs 16:9) in favor of consistent 16:9
- Ensures thumbnails maintain proper proportions on both iOS and macOS
This provides consistent sizing across platforms and eliminates the jump when images finish loading.
Thumbnails were being stretched vertically due to incorrect aspect ratio handling. Fixed by:
- Using .scaledToFill() on thumbnails to fill the container width
- Constraining container to 16:9 aspect ratio with .fit mode
- Adding matching aspect ratio to placeholder to prevent layout shift during loading
This ensures thumbnails maintain proper proportions while filling the full cell width.
Reduced video cell and grid item sizes on tvOS to improve layout spacing
and visual consistency. Changed grid item size from 600 to 560 pixels,
and adjusted video cell frame dimensions accordingly.
This commit addresses crashes caused by race conditions when accessing audio track arrays:
- MPVBackend.swift: Use safe index clamping to prevent array out of bounds crashes when selecting audio tracks
- PlayerModel.swift: Add selectedAudioTrack computed property for thread-safe audio track access
- ControlsOverlay.swift: Use safe accessor with "Original" fallback label
- PlaybackSettings.swift: Use safe accessor with "Original" fallback label
This fix resolves approximately 37% of crashes (23 out of 62 crash logs) that were caused by index out of range errors in MPVBackend.playStream at line 345.
Fixed improperly sized and positioned thumbnails by removing duplicate aspect ratio constraints and standardizing to 4:3 format with fill content mode for better display.
Switch from VStack to ZStack layout for better control over detail view positioning in fullscreen mode. Add z-index layering to ensure proper stacking order of player backend and video details.
Remove unnecessary edgesIgnoringSafeArea modifier and simplify status bar hiding logic by removing iPad-specific conditional checks, making the fullscreen behavior more consistent across iOS devices.
Add availability check for tvOS 17.0+ when using Menu with primaryAction parameter. Falls back to simple Button for tvOS 15.0-16.x to maintain backward compatibility with the deployment target.
Add visible labels for all pickers in settings on macOS by wrapping them
in HStack with Text labels and Spacer() for proper alignment.
Fixed pickers:
- BrowsingSettings: Startup section, Thumbnails quality, Player bar gestures
- PlayerControlsSettings: Action button labels
- PlayerSettings: Source, Inspector, Caption size/color/languages, Sidebar
All picker labels now consistently display with left-aligned text and
right-aligned picker controls on macOS.
- Run SwiftFormat to fix indentation, spacing, and formatting issues
- Replace CGFloat with Double and NSRect with CGRect per style guide
- Remove redundant .center alignment specifications
- Remove unnecessary @available checks for satisfied deployment targets
- Fix closure brace indentation for consistency
- Disable closure_end_indentation rule to resolve SwiftFormat conflict
All linting checks now pass with zero errors and warnings.
Wrap favoritesChanged.toggle() calls in MainActor.run blocks to ensure
main actor-isolated state mutations happen on the correct actor context.
This resolves Swift concurrency warnings when updating state from
nonisolated async contexts.
Modified HorizontalCells to conditionally apply edgesIgnoringSafeArea based on navigation style. In sidebar mode (iPad), content now respects safe areas and won't overlap with the sidebar. In tab mode (iPhone), content maintains full-width scrolling behavior.
When displaying the video details overlay on iPad in non-fullscreen windows,
add 65px of left padding (50px for system controls width + 15px spacing) to
prevent content from overlapping with iPad system controls.
When the iPad window is resized (not fullscreen), player controls now have 10px horizontal padding from the edges for better spacing and visual comfort.
Adds fullscreen detection utility to Constants.swift to determine if the window occupies the full screen on iOS. Uses this to conditionally add leading padding to player controls on iPad in non-fullscreen windows, preventing overlap with system window controls.
When playing video fullscreen in a resizable window on iPad, the player
height was being forced to UIScreen.main.bounds.size.height, which is
the full screen size. In resizable windows, this caused the player
container to extend beyond the visible window bounds, clipping controls
at the bottom.
Now on iPad, the player uses natural geometry provided by its container
which respects actual window bounds, while iPhone continues using
screen-based calculation for proper fullscreen behavior.
Added plain button style for rate increase/decrease buttons on iOS. Fixed safe area insets in VerticalCells to respect sidebar navigation style on iOS.
Added height reservation to FavoriteItemView to prevent layout shifts during content loading. Changed HomeView to use LazyVStack for better performance. Converted QueueView from LazyVStack to VStack. Disabled animations on content count changes across multiple views to prevent jarring layout transitions. Added width constraint to stream button in PlaybackSettings.
Removed border overlay on search text field for macOS 26+ to match new design guidelines. Added conditional padding to sort label for better alignment on macOS 26+.
Standardized picker and button sizing with consistent alignment and control sizes. Added SettingsPickerModifier to all macOS pickers with menu style. Improved rate buttons with proper sizing and alignment. Added text truncation for stream descriptions to prevent overflow.
Restructured PlayerControls view hierarchy by extracting controls content into a separate computed property for better code organization. Added shouldShowCustomControls property to VideoPlayerView to properly determine when custom controls should be shown vs system controls. Updated hover logic to only show/hide custom controls when appropriate.
- Make glassEffect iOS-only as it's not available on other platforms
- Use ultraThinMaterial fallback for macOS and tvOS
- Fixes build error in GitHub Actions with Xcode 16.4
This commit resolves multiple build errors caused by using APIs that
require newer OS versions than the deployment targets (macOS 11.0 and
tvOS 15.0).
macOS fixes:
- Add missing init(frame:) initializer to PlayerLayerView
- Add availability checks for textSelection modifier (macOS 12.0+)
- Add availability checks for AttributedString (macOS 12.0+)
- Add availability checks for listStyle.inset(alternatesRowBackgrounds:) (macOS 12.0+)
- Add availability checks for focusScope modifier (macOS 12.0+)
- Correct listRowSeparator availability from macOS 12.0 to 13.0
tvOS fixes:
- Use older onChange(of:) signature compatible with tvOS 15.0
- Add availability check for Menu with primaryAction (tvOS 17.0+)
All changes include appropriate fallbacks for older OS versions to
maintain backward compatibility.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>