From ce7ba207ea809ebf5dac8cafffe194470d06ce10 Mon Sep 17 00:00:00 2001 From: Arkadiusz Fal Date: Sun, 9 Nov 2025 18:53:06 +0100 Subject: [PATCH] Fix API availability issues for macOS 11.0 and tvOS 15.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- Backports/ListRowSeparator+Backport.swift | 2 +- Shared/Channels/ChannelVideosView.swift | 22 ++++++---- Shared/Player/PlayerLayerView.swift | 5 +++ Shared/Player/Video Details/CommentView.swift | 14 +++++- .../Video Details/VideoDescription.swift | 27 ++++++++---- Shared/Settings/QualityProfileForm.swift | 7 ++- Shared/Settings/QualitySettings.swift | 13 ++++-- Shared/Subscriptions/FeedView.swift | 44 +++++++++++++------ Shared/Trending/TrendingCountry.swift | 7 ++- macOS/InstancesSettings.swift | 7 ++- 10 files changed, 106 insertions(+), 42 deletions(-) diff --git a/Backports/ListRowSeparator+Backport.swift b/Backports/ListRowSeparator+Backport.swift index 1ca100ee..82134c25 100644 --- a/Backports/ListRowSeparator+Backport.swift +++ b/Backports/ListRowSeparator+Backport.swift @@ -5,7 +5,7 @@ extension Backport where Content: View { @ViewBuilder func listRowSeparator(_ visible: Bool) -> some View { #if !os(tvOS) // swiftlint:disable:next deployment_target - if #available(iOS 15.0, macOS 12.0, *) { + if #available(iOS 15.0, macOS 13.0, *) { content .listRowSeparator(visible ? .visible : .hidden) } else { diff --git a/Shared/Channels/ChannelVideosView.swift b/Shared/Channels/ChannelVideosView.swift index d1d02f5c..9c2f1bf2 100644 --- a/Shared/Channels/ChannelVideosView.swift +++ b/Shared/Channels/ChannelVideosView.swift @@ -181,15 +181,19 @@ struct ChannelVideosView: View { .navigationTitle(navigationTitle) #endif - return Group { - content - #if os(tvOS) - .background(Color.background(scheme: colorScheme)) - #endif - #if !os(iOS) - .focusScope(focusNamespace) - #endif - } + #if os(tvOS) + return content + .background(Color.background(scheme: colorScheme)) + .focusScope(focusNamespace) + #elseif os(macOS) + if #available(macOS 12.0, *) { + return content.focusScope(focusNamespace) + } else { + return content + } + #else + return content + #endif } var verticalCellsEdgesIgnoringSafeArea: Edge.Set { diff --git a/Shared/Player/PlayerLayerView.swift b/Shared/Player/PlayerLayerView.swift index ff2d865c..7f19f269 100644 --- a/Shared/Player/PlayerLayerView.swift +++ b/Shared/Player/PlayerLayerView.swift @@ -16,6 +16,11 @@ import Foundation player.avPlayerBackend.playerLayer } + override init(frame frameRect: NSRect) { + super.init(frame: frameRect) + wantsLayer = true + } + required init?(coder: NSCoder) { super.init(coder: coder) } diff --git a/Shared/Player/Video Details/CommentView.swift b/Shared/Player/Video Details/CommentView.swift index 514d51b4..70b49894 100644 --- a/Shared/Player/Video Details/CommentView.swift +++ b/Shared/Player/Video Details/CommentView.swift @@ -238,7 +238,7 @@ struct CommentView: View { .font(.system(size: 14)) .lineSpacing(3) .fixedSize(horizontal: false, vertical: true) - .textSelection(.enabled) + .modifier(TextSelectionModifier()) #else Text(comment.text) #endif @@ -253,6 +253,18 @@ struct CommentView: View { } } +#if os(macOS) + struct TextSelectionModifier: ViewModifier { + func body(content: Content) -> some View { + if #available(macOS 12.0, *) { + content.textSelection(.enabled) + } else { + content + } + } + } +#endif + #if os(iOS) struct ActiveLabelCommentRepresentable: UIViewRepresentable { var text: String diff --git a/Shared/Player/Video Details/VideoDescription.swift b/Shared/Player/Video Details/VideoDescription.swift index 737ee929..7335e528 100644 --- a/Shared/Player/Video Details/VideoDescription.swift +++ b/Shared/Player/Video Details/VideoDescription.swift @@ -58,19 +58,30 @@ struct VideoDescription: View { @ViewBuilder var textDescription: some View { #if canImport(AppKit) - DescriptionWithLinks(description: description, detailsSize: detailsSize) - .frame(maxWidth: .infinity, alignment: .leading) - .lineLimit(expand ? 500 : collapsedLinesDescription) - .textSelection(.enabled) - .multilineTextAlignment(.leading) - .font(.system(size: 14)) - .lineSpacing(3) - .allowsHitTesting(expand) + if #available(macOS 12.0, *) { + DescriptionWithLinks(description: description, detailsSize: detailsSize) + .frame(maxWidth: .infinity, alignment: .leading) + .lineLimit(expand ? 500 : collapsedLinesDescription) + .textSelection(.enabled) + .multilineTextAlignment(.leading) + .font(.system(size: 14)) + .lineSpacing(3) + .allowsHitTesting(expand) + } else { + Text(description) + .frame(maxWidth: .infinity, alignment: .leading) + .lineLimit(expand ? 500 : collapsedLinesDescription) + .multilineTextAlignment(.leading) + .font(.system(size: 14)) + .lineSpacing(3) + .allowsHitTesting(expand) + } #endif } // If possibe convert URLs to clickable links #if canImport(AppKit) + @available(macOS 12.0, *) struct DescriptionWithLinks: View { let description: String let detailsSize: CGSize? diff --git a/Shared/Settings/QualityProfileForm.swift b/Shared/Settings/QualityProfileForm.swift index 005d2965..a4a73552 100644 --- a/Shared/Settings/QualityProfileForm.swift +++ b/Shared/Settings/QualityProfileForm.swift @@ -242,8 +242,11 @@ struct QualityProfileForm: View { #if os(macOS) let list = filteredFormatList - list - .listStyle(.inset(alternatesRowBackgrounds: true)) + if #available(macOS 12.0, *) { + list.listStyle(.inset(alternatesRowBackgrounds: true)) + } else { + list.listStyle(.inset) + } Spacer() #else filteredFormatList diff --git a/Shared/Settings/QualitySettings.swift b/Shared/Settings/QualitySettings.swift index 98715e17..1ab182d4 100644 --- a/Shared/Settings/QualitySettings.swift +++ b/Shared/Settings/QualitySettings.swift @@ -183,10 +183,17 @@ struct QualitySettings: View { } #if os(macOS) - List { - list + if #available(macOS 12.0, *) { + List { + list + } + .listStyle(.inset(alternatesRowBackgrounds: true)) + } else { + List { + list + } + .listStyle(.inset) } - .listStyle(.inset(alternatesRowBackgrounds: true)) #else list #endif diff --git a/Shared/Subscriptions/FeedView.swift b/Shared/Subscriptions/FeedView.swift index ee69ccbd..ed748270 100644 --- a/Shared/Subscriptions/FeedView.swift +++ b/Shared/Subscriptions/FeedView.swift @@ -156,7 +156,7 @@ struct FeedView: View { .focused(self.$focusedChannel, equals: channel.id) } } - .onChange(of: self.focusedChannel) { + .onChange(of: self.focusedChannel) { _ in if self.focusedChannel == "all" { withAnimation { self.selectedChannel = nil @@ -223,21 +223,37 @@ struct FeedView: View { var header: some View { HStack(spacing: 16) { #if os(tvOS) - Menu { - accountsPicker - } label: { - Label("Channels", systemImage: "filemenu.and.selection") - .labelStyle(.iconOnly) - .imageScale(.small) - .font(.caption) - } primaryAction: { - withAnimation { - self.feedChannelsViewVisible = true - self.focusedChannel = selectedChannel?.id ?? "all" + if #available(tvOS 17.0, *) { + Menu { + accountsPicker + } label: { + Label("Channels", systemImage: "filemenu.and.selection") + .labelStyle(.iconOnly) + .imageScale(.small) + .font(.caption) + } primaryAction: { + withAnimation { + self.feedChannelsViewVisible = true + self.focusedChannel = selectedChannel?.id ?? "all" + } } + .opacity(feedChannelsViewVisible ? 0 : 1) + .frame(minWidth: feedChannelsViewVisible ? 0 : nil, maxWidth: feedChannelsViewVisible ? 0 : nil) + } else { + Button { + withAnimation { + self.feedChannelsViewVisible = true + self.focusedChannel = selectedChannel?.id ?? "all" + } + } label: { + Label("Channels", systemImage: "filemenu.and.selection") + .labelStyle(.iconOnly) + .imageScale(.small) + .font(.caption) + } + .opacity(feedChannelsViewVisible ? 0 : 1) + .frame(minWidth: feedChannelsViewVisible ? 0 : nil, maxWidth: feedChannelsViewVisible ? 0 : nil) } - .opacity(feedChannelsViewVisible ? 0 : 1) - .frame(minWidth: feedChannelsViewVisible ? 0 : nil, maxWidth: feedChannelsViewVisible ? 0 : nil) channelHeaderView if selectedChannel == nil { Spacer() diff --git a/Shared/Trending/TrendingCountry.swift b/Shared/Trending/TrendingCountry.swift index f8bbd37b..f2c4fda1 100644 --- a/Shared/Trending/TrendingCountry.swift +++ b/Shared/Trending/TrendingCountry.swift @@ -58,8 +58,11 @@ struct TrendingCountry: View { return Group { #if os(macOS) - list - .listStyle(.inset(alternatesRowBackgrounds: true)) + if #available(macOS 12.0, *) { + list.listStyle(.inset(alternatesRowBackgrounds: true)) + } else { + list.listStyle(.inset) + } #else list #endif diff --git a/macOS/InstancesSettings.swift b/macOS/InstancesSettings.swift index 806de418..2ea61445 100644 --- a/macOS/InstancesSettings.swift +++ b/macOS/InstancesSettings.swift @@ -71,8 +71,11 @@ struct InstancesSettings: View { } } - list - .listStyle(.inset(alternatesRowBackgrounds: true)) + if #available(macOS 12.0, *) { + list.listStyle(.inset(alternatesRowBackgrounds: true)) + } else { + list.listStyle(.inset) + } } if selectedInstance != nil, selectedInstance.app.hasFrontendURL {