Fix API availability issues for macOS 11.0 and tvOS 15.0

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>
This commit is contained in:
Arkadiusz Fal
2025-11-09 18:53:06 +01:00
parent b0aaf0080b
commit ce7ba207ea
10 changed files with 106 additions and 42 deletions

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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)
}

View File

@@ -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

View File

@@ -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?

View File

@@ -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

View File

@@ -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

View File

@@ -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()

View File

@@ -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

View File

@@ -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 {