mirror of
https://github.com/yattee/yattee.git
synced 2025-11-13 05:38:45 +00:00
Fix all SwiftLint violations across codebase
Resolves 130+ violations including deployment target checks, code style issues, and formatting inconsistencies. Adds SwiftLint disable comments for compiler-required availability checks while maintaining deployment target compliance. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -182,17 +182,13 @@ struct ChannelVideosView: View {
|
||||
#endif
|
||||
|
||||
return Group {
|
||||
if #available(macOS 12.0, *) {
|
||||
content
|
||||
#if os(tvOS)
|
||||
.background(Color.background(scheme: colorScheme))
|
||||
#endif
|
||||
#if !os(iOS)
|
||||
.focusScope(focusNamespace)
|
||||
#endif
|
||||
} else {
|
||||
content
|
||||
}
|
||||
content
|
||||
#if os(tvOS)
|
||||
.background(Color.background(scheme: colorScheme))
|
||||
#endif
|
||||
#if !os(iOS)
|
||||
.focusScope(focusNamespace)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -150,10 +150,8 @@ enum Constants {
|
||||
let iOS15 = [5]
|
||||
let iconName = "go\(type).\(interval)"
|
||||
|
||||
if #available(iOS 15, macOS 12, *) {
|
||||
if iOS15.contains(interval) {
|
||||
return iconName
|
||||
}
|
||||
if iOS15.contains(interval) {
|
||||
return iconName
|
||||
}
|
||||
|
||||
if allVersions.contains(interval) {
|
||||
|
||||
@@ -713,7 +713,7 @@ enum SponsorBlockColors: String {
|
||||
case music_offtopic = "#FF9900" // Orange
|
||||
|
||||
// Define all cases, can be used to iterate over the colors
|
||||
static let allCases: [SponsorBlockColors] = [Self.sponsor, Self.selfpromo, Self.interaction, Self.intro, Self.outro, Self.preview, Self.filler, Self.music_offtopic]
|
||||
static let allCases: [Self] = [Self.sponsor, Self.selfpromo, Self.interaction, Self.intro, Self.outro, Self.preview, Self.filler, Self.music_offtopic]
|
||||
|
||||
// Create a dictionary with the category names as keys and colors as values
|
||||
static let dictionary: [String: String] = {
|
||||
|
||||
@@ -200,19 +200,16 @@ struct FavoriteItemView: View {
|
||||
let limit = favoritesModel.limit(item)
|
||||
if item.section == .history {
|
||||
return Array(visibleWatches.prefix(limit).map { ContentItem(video: player.historyVideo($0.videoID) ?? $0.video) })
|
||||
} else {
|
||||
var result = [ContentItem]()
|
||||
result.reserveCapacity(min(store.contentItems.count, limit))
|
||||
for contentItem in store.contentItems {
|
||||
if itemVisible(contentItem) {
|
||||
result.append(contentItem)
|
||||
if result.count >= limit {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
var result = [ContentItem]()
|
||||
result.reserveCapacity(min(store.contentItems.count, limit))
|
||||
for contentItem in store.contentItems where itemVisible(contentItem) {
|
||||
result.append(contentItem)
|
||||
if result.count >= limit {
|
||||
break
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func itemVisible(_ item: ContentItem) -> Bool {
|
||||
|
||||
@@ -15,14 +15,10 @@ struct AccountViewButton: View {
|
||||
} label: {
|
||||
HStack(spacing: 6) {
|
||||
if !accountPickerDisplaysUsername || !(model.current?.isPublic ?? true) {
|
||||
if #available(iOS 15, macOS 12, *) {
|
||||
if let name = model.current?.app?.rawValue.capitalized {
|
||||
Image(name)
|
||||
.resizable()
|
||||
.frame(width: accountImageSize, height: accountImageSize)
|
||||
} else {
|
||||
Image(systemName: "globe")
|
||||
}
|
||||
if let name = model.current?.app?.rawValue.capitalized {
|
||||
Image(name)
|
||||
.resizable()
|
||||
.frame(width: accountImageSize, height: accountImageSize)
|
||||
} else {
|
||||
Image(systemName: "globe")
|
||||
}
|
||||
|
||||
@@ -114,6 +114,7 @@ import SwiftUI
|
||||
func setupController() {
|
||||
controller.delegate = PlayerModel.shared.appleAVPlayerViewControllerDelegate
|
||||
controller.allowsPictureInPicturePlayback = true
|
||||
// swiftlint:disable:next deployment_target
|
||||
if #available(iOS 14.2, *) {
|
||||
controller.canStartPictureInPictureAutomaticallyFromInline = true
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ struct ControlBackgroundModifier: ViewModifier {
|
||||
|
||||
func body(content: Content) -> some View {
|
||||
if enabled {
|
||||
// swiftlint:disable:next deployment_target
|
||||
if #available(iOS 15, macOS 12, *) {
|
||||
content
|
||||
.background(.thinMaterial)
|
||||
|
||||
@@ -3,6 +3,7 @@ import SwiftUI
|
||||
|
||||
extension Backport where Content: View {
|
||||
@ViewBuilder func playbackSettingsPresentationDetents() -> some View {
|
||||
// swiftlint:disable:next deployment_target
|
||||
if #available(iOS 16.0, macOS 13.0, tvOS 16.0, *) {
|
||||
content
|
||||
.presentationDetents([.height(400), .large])
|
||||
|
||||
@@ -12,10 +12,6 @@ import Foundation
|
||||
wantsLayer = true
|
||||
}}
|
||||
|
||||
override init(frame frameRect: CGRect) {
|
||||
super.init(frame: frameRect)
|
||||
}
|
||||
|
||||
override func makeBackingLayer() -> CALayer {
|
||||
player.avPlayerBackend.playerLayer
|
||||
}
|
||||
@@ -28,12 +24,13 @@ import Foundation
|
||||
final class PlayerLayerView: UIView {
|
||||
var player: PlayerModel { .shared }
|
||||
|
||||
private var layerAdded = false
|
||||
|
||||
// swiftlint:disable:next unneeded_override
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
}
|
||||
|
||||
private var layerAdded = false
|
||||
|
||||
@available(*, unavailable)
|
||||
required init?(coder _: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
|
||||
@@ -7,7 +7,7 @@ import SwiftUI
|
||||
struct CommentView: View {
|
||||
let comment: Comment
|
||||
@Binding var repliesID: Comment.ID?
|
||||
var availableWidth: CGFloat
|
||||
var availableWidth: Double
|
||||
|
||||
@State private var subscribed = false
|
||||
|
||||
@@ -228,27 +228,20 @@ struct CommentView: View {
|
||||
private var commentText: some View {
|
||||
Group {
|
||||
let rawText = comment.text
|
||||
if #available(iOS 15.0, macOS 12.0, *) {
|
||||
#if os(iOS)
|
||||
ActiveLabelCommentRepresentable(
|
||||
text: rawText,
|
||||
availableWidth: availableWidth
|
||||
)
|
||||
#elseif os(macOS)
|
||||
Text(rawText)
|
||||
.font(.system(size: 14))
|
||||
.lineSpacing(3)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.textSelection(.enabled)
|
||||
#else
|
||||
Text(comment.text)
|
||||
#endif
|
||||
} else {
|
||||
#if os(iOS)
|
||||
ActiveLabelCommentRepresentable(
|
||||
text: rawText,
|
||||
availableWidth: availableWidth
|
||||
)
|
||||
#elseif os(macOS)
|
||||
Text(rawText)
|
||||
.font(.system(size: 15))
|
||||
.font(.system(size: 14))
|
||||
.lineSpacing(3)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
}
|
||||
.textSelection(.enabled)
|
||||
#else
|
||||
Text(comment.text)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -263,7 +256,7 @@ struct CommentView: View {
|
||||
#if os(iOS)
|
||||
struct ActiveLabelCommentRepresentable: UIViewRepresentable {
|
||||
var text: String
|
||||
var availableWidth: CGFloat
|
||||
var availableWidth: Double
|
||||
|
||||
@State private var label = ActiveLabel()
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ struct CommentsView: View {
|
||||
|
||||
struct CommentsView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
// swiftlint:disable:next deployment_target
|
||||
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, *) {
|
||||
CommentsView()
|
||||
.previewInterfaceOrientation(.landscapeRight)
|
||||
|
||||
@@ -80,14 +80,16 @@ struct InspectorView: View {
|
||||
.foregroundColor(.secondary)
|
||||
Spacer()
|
||||
let value = Text(value).lineLimit(1)
|
||||
if #available(iOS 15.0, macOS 12.0, *) {
|
||||
#if !os(tvOS)
|
||||
// swiftlint:disable:next deployment_target
|
||||
if #available(iOS 15.0, macOS 12.0, *) {
|
||||
value.textSelection(.enabled)
|
||||
} else {
|
||||
value
|
||||
}
|
||||
#else
|
||||
value
|
||||
#if !os(tvOS)
|
||||
.textSelection(.enabled)
|
||||
#endif
|
||||
} else {
|
||||
value
|
||||
}
|
||||
#endif
|
||||
}
|
||||
.font(.caption)
|
||||
}
|
||||
|
||||
@@ -58,28 +58,19 @@ struct VideoDescription: View {
|
||||
|
||||
@ViewBuilder var textDescription: some View {
|
||||
#if canImport(AppKit)
|
||||
Group {
|
||||
if #available(macOS 12, *) {
|
||||
DescriptionWithLinks(description: description, detailsSize: detailsSize)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.lineLimit(expand ? 500 : collapsedLinesDescription)
|
||||
.textSelection(.enabled)
|
||||
} else {
|
||||
Text(description)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.lineLimit(expand ? 500 : collapsedLinesDescription)
|
||||
}
|
||||
}
|
||||
.multilineTextAlignment(.leading)
|
||||
.font(.system(size: 14))
|
||||
.lineSpacing(3)
|
||||
.allowsHitTesting(expand)
|
||||
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)
|
||||
#endif
|
||||
}
|
||||
|
||||
// If possibe convert URLs to clickable links
|
||||
#if canImport(AppKit)
|
||||
@available(macOS 12, *)
|
||||
struct DescriptionWithLinks: View {
|
||||
let description: String
|
||||
let detailsSize: CGSize?
|
||||
|
||||
@@ -49,6 +49,7 @@ struct VideoDetails: View {
|
||||
.padding(.trailing, 5)
|
||||
// TODO: when setting tvOS minimum to 16, the platform modifier can be removed
|
||||
#if !os(tvOS)
|
||||
.accessibilityAddTraits(.isButton)
|
||||
.simultaneousGesture(
|
||||
TapGesture() // Ensures the button tap is recognized
|
||||
)
|
||||
@@ -63,11 +64,11 @@ struct VideoDetails: View {
|
||||
.lineLimit(1)
|
||||
// TODO: when setting tvOS minimum to 16, the platform modifier can be removed
|
||||
#if !os(tvOS)
|
||||
.accessibilityAddTraits(.isButton)
|
||||
.onTapGesture {
|
||||
guard let channel = video?.channel else { return }
|
||||
NavigationModel.shared.openChannel(channel, navigationStyle: .sidebar)
|
||||
}
|
||||
.accessibilityAddTraits(.isButton)
|
||||
#endif
|
||||
} else if model.videoBeingOpened != nil {
|
||||
Text("Yattee")
|
||||
|
||||
@@ -151,9 +151,9 @@ struct PlaylistsView: View {
|
||||
}
|
||||
#else
|
||||
.onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in
|
||||
model.load()
|
||||
loadResource()
|
||||
}
|
||||
model.load()
|
||||
loadResource()
|
||||
}
|
||||
#endif
|
||||
#if !os(tvOS)
|
||||
.background(
|
||||
|
||||
@@ -2,7 +2,6 @@ import Repeat
|
||||
import SwiftUI
|
||||
import SwiftUIIntrospect
|
||||
|
||||
@available(iOS 15.0, macOS 12, *)
|
||||
struct FocusableSearchTextField: View {
|
||||
@ObservedObject private var state = SearchModel.shared
|
||||
|
||||
|
||||
@@ -57,13 +57,8 @@ struct SearchView: View {
|
||||
.environment(\.listingStyle, searchListingStyle)
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .principal) {
|
||||
if #available(iOS 15, *) {
|
||||
FocusableSearchTextField()
|
||||
.frame(width: searchFieldWidth(geometry.size.width))
|
||||
} else {
|
||||
SearchTextField()
|
||||
.frame(width: searchFieldWidth(geometry.size.width))
|
||||
}
|
||||
FocusableSearchTextField()
|
||||
.frame(width: searchFieldWidth(geometry.size.width))
|
||||
}
|
||||
ToolbarItem(placement: .navigationBarTrailing) {
|
||||
searchMenu
|
||||
@@ -227,11 +222,7 @@ struct SearchView: View {
|
||||
filtersMenu
|
||||
}
|
||||
|
||||
if #available(macOS 12, *) {
|
||||
FocusableSearchTextField()
|
||||
} else {
|
||||
SearchTextField()
|
||||
}
|
||||
FocusableSearchTextField()
|
||||
}
|
||||
}
|
||||
.onAppear {
|
||||
@@ -650,21 +641,21 @@ struct SearchView: View {
|
||||
}
|
||||
|
||||
#if os(iOS)
|
||||
private func searchFieldWidth(_ viewWidth: CGFloat) -> CGFloat {
|
||||
private func searchFieldWidth(_ viewWidth: Double) -> Double {
|
||||
// Base padding for internal SearchTextField padding (16pt each side = 32 total)
|
||||
var totalDeduction: CGFloat = 32
|
||||
|
||||
var totalDeduction: Double = 32
|
||||
|
||||
// Add space for trailing menu button
|
||||
totalDeduction += 44
|
||||
|
||||
|
||||
// Add space for sidebar toggle button if in sidebar navigation style
|
||||
if navigationStyle == .sidebar {
|
||||
totalDeduction += 44
|
||||
}
|
||||
|
||||
|
||||
// Minimum width to ensure usability
|
||||
let minWidth: CGFloat = 200
|
||||
|
||||
let minWidth: Double = 200
|
||||
|
||||
return max(minWidth, viewWidth - totalDeduction)
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -84,13 +84,14 @@ struct AdvancedSettings: View {
|
||||
Text("cache-pause-initial")
|
||||
#if !os(tvOS)
|
||||
Image(systemName: "link")
|
||||
.accessibilityAddTraits([.isButton, .isLink])
|
||||
.font(.footnote)
|
||||
#if os(iOS)
|
||||
.accessibilityAddTraits([.isButton, .isLink])
|
||||
.onTapGesture {
|
||||
UIApplication.shared.open(URL(string: "https://mpv.io/manual/stable/#options-cache-pause-initial")!)
|
||||
}
|
||||
#elseif os(macOS)
|
||||
.accessibilityAddTraits([.isButton, .isLink])
|
||||
.onTapGesture {
|
||||
NSWorkspace.shared.open(URL(string: "https://mpv.io/manual/stable/#options-cache-pause-initial")!)
|
||||
}
|
||||
@@ -104,13 +105,14 @@ struct AdvancedSettings: View {
|
||||
Text("cache-secs")
|
||||
#if !os(tvOS)
|
||||
Image(systemName: "link")
|
||||
.accessibilityAddTraits([.isButton, .isLink])
|
||||
.font(.footnote)
|
||||
#if os(iOS)
|
||||
.accessibilityAddTraits([.isButton, .isLink])
|
||||
.onTapGesture {
|
||||
UIApplication.shared.open(URL(string: "https://mpv.io/manual/stable/#options-cache-secs")!)
|
||||
}
|
||||
#elseif os(macOS)
|
||||
.accessibilityAddTraits([.isButton, .isLink])
|
||||
.onTapGesture {
|
||||
NSWorkspace.shared.open(URL(string: "https://mpv.io/manual/stable/#options-cache-secs")!)
|
||||
}
|
||||
@@ -130,13 +132,14 @@ struct AdvancedSettings: View {
|
||||
Text("cache-pause-wait")
|
||||
#if !os(tvOS)
|
||||
Image(systemName: "link")
|
||||
.accessibilityAddTraits([.isButton, .isLink])
|
||||
.font(.footnote)
|
||||
#if os(iOS)
|
||||
.accessibilityAddTraits([.isButton, .isLink])
|
||||
.onTapGesture {
|
||||
UIApplication.shared.open(URL(string: "https://mpv.io/manual/stable/#options-cache-pause-wait")!)
|
||||
}
|
||||
#elseif os(macOS)
|
||||
.accessibilityAddTraits([.isButton, .isLink])
|
||||
.onTapGesture {
|
||||
NSWorkspace.shared.open(URL(string: "https://mpv.io/manual/stable/#options-cache-pause-wait")!)
|
||||
}
|
||||
@@ -157,13 +160,14 @@ struct AdvancedSettings: View {
|
||||
Text("deinterlace")
|
||||
#if !os(tvOS)
|
||||
Image(systemName: "link")
|
||||
.accessibilityAddTraits([.isButton, .isLink])
|
||||
.font(.footnote)
|
||||
#if os(iOS)
|
||||
.accessibilityAddTraits([.isButton, .isLink])
|
||||
.onTapGesture {
|
||||
UIApplication.shared.open(URL(string: "https://mpv.io/manual/stable/#options-deinterlace")!)
|
||||
}
|
||||
#elseif os(macOS)
|
||||
.accessibilityAddTraits([.isButton, .isLink])
|
||||
.onTapGesture {
|
||||
NSWorkspace.shared.open(URL(string: "https://mpv.io/manual/stable/#options-deinterlace")!)
|
||||
}
|
||||
@@ -178,13 +182,14 @@ struct AdvancedSettings: View {
|
||||
Text("initial-audio-sync")
|
||||
#if !os(tvOS)
|
||||
Image(systemName: "link")
|
||||
.accessibilityAddTraits([.isButton, .isLink])
|
||||
.font(.footnote)
|
||||
#if os(iOS)
|
||||
.accessibilityAddTraits([.isButton, .isLink])
|
||||
.onTapGesture {
|
||||
UIApplication.shared.open(URL(string: "https://mpv.io/manual/stable/#options-initial-audio-sync")!)
|
||||
}
|
||||
#elseif os(macOS)
|
||||
.accessibilityAddTraits([.isButton, .isLink])
|
||||
.onTapGesture {
|
||||
NSWorkspace.shared.open(URL(string: "https://mpv.io/manual/stable/#options-initial-audio-sync")!)
|
||||
}
|
||||
@@ -199,13 +204,14 @@ struct AdvancedSettings: View {
|
||||
|
||||
#if !os(tvOS)
|
||||
Image(systemName: "link")
|
||||
.accessibilityAddTraits([.isButton, .isLink])
|
||||
.font(.footnote)
|
||||
#if os(iOS)
|
||||
.accessibilityAddTraits([.isButton, .isLink])
|
||||
.onTapGesture {
|
||||
UIApplication.shared.open(URL(string: "https://mpv.io/manual/stable/#options-hwdec")!)
|
||||
}
|
||||
#elseif os(macOS)
|
||||
.accessibilityAddTraits([.isButton, .isLink])
|
||||
.onTapGesture {
|
||||
NSWorkspace.shared.open(URL(string: "https://mpv.io/manual/stable/#options-hwdec")!)
|
||||
}
|
||||
@@ -228,13 +234,14 @@ struct AdvancedSettings: View {
|
||||
|
||||
#if !os(tvOS)
|
||||
Image(systemName: "link")
|
||||
.accessibilityAddTraits([.isButton, .isLink])
|
||||
.font(.footnote)
|
||||
#if os(iOS)
|
||||
.accessibilityAddTraits([.isButton, .isLink])
|
||||
.onTapGesture {
|
||||
UIApplication.shared.open(URL(string: "https://mpv.io/manual/stable/#options-demuxer-lavf-probe-info")!)
|
||||
}
|
||||
#elseif os(macOS)
|
||||
.accessibilityAddTraits([.isButton, .isLink])
|
||||
.onTapGesture {
|
||||
NSWorkspace.shared.open(URL(string: "https://mpv.io/manual/stable/#options-demuxer-lavf-probe-info")!)
|
||||
}
|
||||
|
||||
@@ -221,12 +221,12 @@ struct HistorySettings: View {
|
||||
.labelStyle(.iconOnly)
|
||||
.padding(7)
|
||||
.foregroundColor(limitRecents ? .accentColor : .gray)
|
||||
.accessibilityAddTraits(.isButton)
|
||||
#if os(iOS)
|
||||
.frame(minHeight: 35)
|
||||
.background(RoundedRectangle(cornerRadius: 4).strokeBorder(lineWidth: 1).foregroundColor(.accentColor))
|
||||
#endif
|
||||
.contentShape(Rectangle())
|
||||
.accessibilityAddTraits(.isButton)
|
||||
.onTapGesture {
|
||||
value.wrappedValue -= 1
|
||||
}
|
||||
@@ -253,11 +253,11 @@ struct HistorySettings: View {
|
||||
.labelStyle(.iconOnly)
|
||||
.padding(7)
|
||||
.foregroundColor(limitRecents ? .accentColor : .gray)
|
||||
.accessibilityAddTraits(.isButton)
|
||||
#if os(iOS)
|
||||
.background(RoundedRectangle(cornerRadius: 4).strokeBorder(lineWidth: 1).foregroundColor(.accentColor))
|
||||
#endif
|
||||
.contentShape(Rectangle())
|
||||
.accessibilityAddTraits(.isButton)
|
||||
.onTapGesture {
|
||||
value.wrappedValue += 1
|
||||
}
|
||||
|
||||
@@ -287,11 +287,11 @@ struct FavoriteItemEditorButton<LabelView: View>: View {
|
||||
.padding(7)
|
||||
.frame(minWidth: 40, minHeight: 40)
|
||||
.foregroundColor(color)
|
||||
.accessibilityAddTraits(.isButton)
|
||||
#if os(iOS)
|
||||
.background(RoundedRectangle(cornerRadius: 4).strokeBorder(lineWidth: 1).foregroundColor(color))
|
||||
#endif
|
||||
.contentShape(Rectangle())
|
||||
.accessibilityAddTraits(.isButton)
|
||||
.onTapGesture(perform: onTapGesture)
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ struct PlayerControlsSettings: View {
|
||||
Text("System controls buttons")
|
||||
.font(.headline)
|
||||
.padding(.vertical, 8)
|
||||
|
||||
|
||||
Button(action: { systemControlsCommands = .seek }) {
|
||||
HStack {
|
||||
Text(labelText("Seek".localized()))
|
||||
@@ -170,8 +170,8 @@ struct PlayerControlsSettings: View {
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.padding(.vertical, 4)
|
||||
|
||||
Button(action: {
|
||||
|
||||
Button(action: {
|
||||
systemControlsCommands = .restartAndAdvanceToNext
|
||||
player.updateRemoteCommandCenter()
|
||||
}) {
|
||||
@@ -301,12 +301,12 @@ struct PlayerControlsSettings: View {
|
||||
.labelStyle(.iconOnly)
|
||||
.padding(7)
|
||||
.foregroundColor(.accentColor)
|
||||
.accessibilityAddTraits(.isButton)
|
||||
#if os(iOS)
|
||||
.frame(minHeight: 35)
|
||||
.background(RoundedRectangle(cornerRadius: 4).strokeBorder(lineWidth: 1).foregroundColor(.accentColor))
|
||||
#endif
|
||||
.contentShape(Rectangle())
|
||||
.accessibilityAddTraits(.isButton)
|
||||
.onTapGesture {
|
||||
var intValue = Int(value.wrappedValue) ?? 10
|
||||
intValue -= 5
|
||||
@@ -337,11 +337,11 @@ struct PlayerControlsSettings: View {
|
||||
.labelStyle(.iconOnly)
|
||||
.padding(7)
|
||||
.foregroundColor(.accentColor)
|
||||
.accessibilityAddTraits(.isButton)
|
||||
#if os(iOS)
|
||||
.background(RoundedRectangle(cornerRadius: 4).strokeBorder(lineWidth: 1).foregroundColor(.accentColor))
|
||||
#endif
|
||||
.contentShape(Rectangle())
|
||||
.accessibilityAddTraits(.isButton)
|
||||
.onTapGesture {
|
||||
var intValue = Int(value.wrappedValue) ?? 10
|
||||
intValue += 5
|
||||
|
||||
@@ -136,19 +136,9 @@ struct QualityProfileForm: View {
|
||||
|
||||
var formatsFooter: some View {
|
||||
VStack(alignment: .leading) {
|
||||
if #available(iOS 16.0, *) {
|
||||
Text("Formats can be reordered and will be selected in this order.")
|
||||
.foregroundColor(.secondary)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
} else if #available(iOS 14.0, *) {
|
||||
Text("Formats will be selected in the order they are listed.")
|
||||
.foregroundColor(.secondary)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
} else {
|
||||
Text("Formats will be selected in the order they are listed.")
|
||||
.foregroundColor(.secondary)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
}
|
||||
Text("Formats can be reordered and will be selected in this order.")
|
||||
.foregroundColor(.secondary)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
|
||||
Text("**Note:** HLS is an adaptive format where specific resolution settings don't apply.")
|
||||
.foregroundColor(.secondary)
|
||||
@@ -252,15 +242,8 @@ struct QualityProfileForm: View {
|
||||
#if os(macOS)
|
||||
let list = filteredFormatList
|
||||
|
||||
Group {
|
||||
if #available(macOS 12.0, *) {
|
||||
list
|
||||
.listStyle(.inset(alternatesRowBackgrounds: true))
|
||||
} else {
|
||||
list
|
||||
.listStyle(.inset)
|
||||
}
|
||||
}
|
||||
list
|
||||
.listStyle(.inset(alternatesRowBackgrounds: true))
|
||||
Spacer()
|
||||
#else
|
||||
filteredFormatList
|
||||
|
||||
@@ -182,24 +182,14 @@ struct QualitySettings: View {
|
||||
}
|
||||
}
|
||||
|
||||
if #available(macOS 12.0, *) {
|
||||
#if os(macOS)
|
||||
List {
|
||||
list
|
||||
}
|
||||
.listStyle(.inset(alternatesRowBackgrounds: true))
|
||||
#else
|
||||
#if os(macOS)
|
||||
List {
|
||||
list
|
||||
#endif
|
||||
} else {
|
||||
#if os(macOS)
|
||||
List {
|
||||
list
|
||||
}
|
||||
#else
|
||||
list
|
||||
#endif
|
||||
}
|
||||
}
|
||||
.listStyle(.inset(alternatesRowBackgrounds: true))
|
||||
#else
|
||||
list
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -190,6 +190,7 @@ struct ChannelsView: View {
|
||||
#if os(iOS)
|
||||
struct CompactListRowModifier: ViewModifier {
|
||||
func body(content: Content) -> some View {
|
||||
// swiftlint:disable:next deployment_target
|
||||
if #available(iOS 15.0, *) {
|
||||
content
|
||||
.listRowSpacing(0)
|
||||
|
||||
@@ -110,8 +110,7 @@ struct FeedView: View {
|
||||
VStack {
|
||||
Text("Channels")
|
||||
.font(.subheadline)
|
||||
if #available(tvOS 17.0, *) {
|
||||
List(selection: $selectedChannel) {
|
||||
List(selection: $selectedChannel) {
|
||||
Button(action: {
|
||||
self.selectedChannel = nil
|
||||
self.feedChannelsViewVisible = false
|
||||
@@ -156,8 +155,8 @@ struct FeedView: View {
|
||||
.buttonStyle(PlainButtonStyle())
|
||||
.focused(self.$focusedChannel, equals: channel.id)
|
||||
}
|
||||
}
|
||||
.onChange(of: self.focusedChannel) {
|
||||
}
|
||||
.onChange(of: self.focusedChannel) {
|
||||
if self.focusedChannel == "all" {
|
||||
withAnimation {
|
||||
self.selectedChannel = nil
|
||||
@@ -171,18 +170,17 @@ struct FeedView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.onAppear {
|
||||
}
|
||||
.onAppear {
|
||||
guard let selectedChannel = self.selectedChannel else {
|
||||
return
|
||||
}
|
||||
proxy.scrollTo(selectedChannel, anchor: .top)
|
||||
}
|
||||
.onExitCommand {
|
||||
}
|
||||
.onExitCommand {
|
||||
withAnimation {
|
||||
self.feedChannelsViewVisible = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -218,30 +216,28 @@ struct FeedView: View {
|
||||
#if !os(macOS)
|
||||
.onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in
|
||||
feed.loadResources()
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
var header: some View {
|
||||
HStack(spacing: 16) {
|
||||
#if os(tvOS)
|
||||
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"
|
||||
}
|
||||
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)
|
||||
}
|
||||
.opacity(feedChannelsViewVisible ? 0 : 1)
|
||||
.frame(minWidth: feedChannelsViewVisible ? 0 : nil, maxWidth: feedChannelsViewVisible ? 0 : nil)
|
||||
channelHeaderView
|
||||
if selectedChannel == nil {
|
||||
Spacer()
|
||||
|
||||
@@ -16,10 +16,11 @@ struct TrendingCountry: View {
|
||||
VStack {
|
||||
#if !os(tvOS)
|
||||
HStack {
|
||||
// swiftlint:disable:next deployment_target
|
||||
if #available(iOS 15.0, macOS 12.0, *) {
|
||||
TextField("Country", text: $query, prompt: Text(Self.prompt))
|
||||
} else {
|
||||
TextField(Self.prompt, text: $query)
|
||||
TextField("Country", text: $query)
|
||||
}
|
||||
|
||||
Button("Done") { selectCountryAndDismiss() }
|
||||
@@ -57,12 +58,8 @@ struct TrendingCountry: View {
|
||||
|
||||
return Group {
|
||||
#if os(macOS)
|
||||
if #available(macOS 12.0, *) {
|
||||
list
|
||||
.listStyle(.inset(alternatesRowBackgrounds: true))
|
||||
} else {
|
||||
list
|
||||
}
|
||||
list
|
||||
.listStyle(.inset(alternatesRowBackgrounds: true))
|
||||
#else
|
||||
list
|
||||
#endif
|
||||
|
||||
@@ -78,12 +78,12 @@ struct TrendingView: View {
|
||||
}
|
||||
#else
|
||||
.sheet(isPresented: $presentingCountrySelection) {
|
||||
TrendingCountry(selectedCountry: $country)
|
||||
#if os(macOS)
|
||||
.frame(minWidth: 400, minHeight: 400)
|
||||
#endif
|
||||
}
|
||||
.background(
|
||||
TrendingCountry(selectedCountry: $country)
|
||||
#if os(macOS)
|
||||
.frame(minWidth: 400, minHeight: 400)
|
||||
#endif
|
||||
}
|
||||
.background(
|
||||
Button("Refresh") {
|
||||
resource.load()
|
||||
.onFailure { self.error = $0 }
|
||||
@@ -131,10 +131,10 @@ struct TrendingView: View {
|
||||
}
|
||||
#else
|
||||
.onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in
|
||||
resource.loadIfNeeded()?
|
||||
.onFailure { self.error = $0 }
|
||||
.onSuccess { _ in self.error = nil }
|
||||
}
|
||||
resource.loadIfNeeded()?
|
||||
.onFailure { self.error = $0 }
|
||||
.onSuccess { _ in self.error = nil }
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -73,7 +73,6 @@ enum URLTester {
|
||||
return
|
||||
}
|
||||
|
||||
// swiftlint:disable:next non_optional_string_data_conversion
|
||||
guard let manifest = String(data: data, encoding: .utf8), !manifest.isEmpty else {
|
||||
Logger(label: "stream.yattee.httpRequest").error("Cannot read or empty HLS manifest")
|
||||
completion([])
|
||||
|
||||
@@ -54,7 +54,8 @@ struct ThumbnailView: View {
|
||||
}
|
||||
|
||||
@ViewBuilder var asyncImageIfAvailable: some View {
|
||||
if #available(iOS 15, macOS 12, *) {
|
||||
// swiftlint:disable:next deployment_target
|
||||
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, *) {
|
||||
CachedAsyncImage(url: url, urlCache: BaseCacheModel.imageCache) { phase in
|
||||
switch phase {
|
||||
case let .success(image):
|
||||
@@ -70,7 +71,7 @@ struct ThumbnailView: View {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
webImage
|
||||
placeholder
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -350,9 +350,9 @@ extension View {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ViewBuilder
|
||||
func applyControlsBackground(enabled: Bool, cornerRadius: CGFloat) -> some View {
|
||||
func applyControlsBackground(enabled: Bool, cornerRadius: Double) -> some View {
|
||||
if enabled {
|
||||
if #available(iOS 26.0, macOS 26.0, tvOS 26.0, *) {
|
||||
// Use Liquid Glass on iOS 26+
|
||||
@@ -360,29 +360,30 @@ extension View {
|
||||
.regular.interactive(),
|
||||
in: .rect(cornerRadius: cornerRadius)
|
||||
)
|
||||
} else if #available(iOS 15.0, macOS 12.0, tvOS 15.0, *) {
|
||||
// Fallback to ultraThinMaterial for iOS 15+
|
||||
self
|
||||
.background(
|
||||
RoundedRectangle(cornerRadius: cornerRadius)
|
||||
.fill(.ultraThinMaterial)
|
||||
)
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: cornerRadius)
|
||||
.stroke(Color("ControlsBorderColor"), lineWidth: 0.5)
|
||||
)
|
||||
} else {
|
||||
// Fallback for iOS 14 and earlier
|
||||
self
|
||||
.background(
|
||||
RoundedRectangle(cornerRadius: cornerRadius)
|
||||
.fill(Color.black.opacity(0.3))
|
||||
.blur(radius: 10)
|
||||
)
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: cornerRadius)
|
||||
.stroke(Color("ControlsBorderColor"), lineWidth: 0.5)
|
||||
)
|
||||
// Fallback to ultraThinMaterial
|
||||
// swiftlint:disable:next deployment_target
|
||||
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, *) {
|
||||
self
|
||||
.background(
|
||||
RoundedRectangle(cornerRadius: cornerRadius)
|
||||
.fill(.ultraThinMaterial)
|
||||
)
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: cornerRadius)
|
||||
.stroke(Color("ControlsBorderColor"), lineWidth: 0.5)
|
||||
)
|
||||
} else {
|
||||
self
|
||||
.background(
|
||||
RoundedRectangle(cornerRadius: cornerRadius)
|
||||
.fill(Color.gray.opacity(0.3))
|
||||
)
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: cornerRadius)
|
||||
.stroke(Color("ControlsBorderColor"), lineWidth: 0.5)
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.background(Color.clear)
|
||||
|
||||
@@ -21,6 +21,7 @@ struct OpenSettingsButton: View {
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
|
||||
// swiftlint:disable:next deployment_target
|
||||
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, *) {
|
||||
button
|
||||
.buttonStyle(.borderedProminent)
|
||||
|
||||
@@ -48,11 +48,12 @@ struct PopularView: View {
|
||||
}
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.refreshControl { refreshControl in
|
||||
resource?.load().onCompletion { _ in
|
||||
refreshControl.endRefreshing()
|
||||
}
|
||||
.onFailure { self.error = $0 }
|
||||
.onSuccess { _ in self.error = nil }
|
||||
resource?.load()
|
||||
.onCompletion { _ in
|
||||
refreshControl.endRefreshing()
|
||||
}
|
||||
.onFailure { self.error = $0 }
|
||||
.onSuccess { _ in self.error = nil }
|
||||
}
|
||||
.backport
|
||||
.refreshable {
|
||||
@@ -80,10 +81,10 @@ struct PopularView: View {
|
||||
}
|
||||
#else
|
||||
.onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in
|
||||
resource?.loadIfNeeded()?
|
||||
.onFailure { self.error = $0 }
|
||||
.onSuccess { _ in self.error = nil }
|
||||
}
|
||||
resource?.loadIfNeeded()?
|
||||
.onFailure { self.error = $0 }
|
||||
.onSuccess { _ in self.error = nil }
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -309,7 +309,8 @@ struct VideoContextMenuView: View {
|
||||
let label = Label("Remove…", systemImage: "trash.fill")
|
||||
.foregroundColor(Color("AppRedColor"))
|
||||
|
||||
if #available(iOS 15, macOS 12, *) {
|
||||
// swiftlint:disable:next deployment_target
|
||||
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, *) {
|
||||
Button(role: .destructive, action: action) { label }
|
||||
} else {
|
||||
Button(action: action) { label }
|
||||
|
||||
@@ -73,15 +73,15 @@ struct YatteeApp: App {
|
||||
)
|
||||
#else
|
||||
.onReceive(
|
||||
NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)
|
||||
) { _ in
|
||||
player.handleEnterForeground()
|
||||
}
|
||||
.onReceive(
|
||||
NotificationCenter.default.publisher(for: UIApplication.didEnterBackgroundNotification)
|
||||
) { _ in
|
||||
player.handleEnterBackground()
|
||||
}
|
||||
NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)
|
||||
) { _ in
|
||||
player.handleEnterForeground()
|
||||
}
|
||||
.onReceive(
|
||||
NotificationCenter.default.publisher(for: UIApplication.didEnterBackgroundNotification)
|
||||
) { _ in
|
||||
player.handleEnterBackground()
|
||||
}
|
||||
#endif
|
||||
#if os(iOS)
|
||||
.handlesExternalEvents(preferring: Set(["*"]), allowing: Set(["*"]))
|
||||
|
||||
Reference in New Issue
Block a user