diff --git a/Shared/Player/Controls/ControlsOverlay.swift b/Shared/Player/Controls/ControlsOverlay.swift index df0e00f6..398520db 100644 --- a/Shared/Player/Controls/ControlsOverlay.swift +++ b/Shared/Player/Controls/ControlsOverlay.swift @@ -11,16 +11,16 @@ struct ControlsOverlay: View { @Default(.qualityProfiles) private var qualityProfiles #if os(tvOS) - enum Field: Hashable { - case qualityProfile - case stream - case increaseRate - case decreaseRate - case captions - } + enum Field: Hashable { + case qualityProfile + case stream + case increaseRate + case decreaseRate + case captions + } - @FocusState private var focusedField: Field? - @State private var presentingButtonHintAlert = false + @FocusState private var focusedField: Field? + @State private var presentingButtonHintAlert = false #endif var body: some View { @@ -94,10 +94,10 @@ struct ControlsOverlay: View { #endif #if os(tvOS) - Text("Press and hold remote button to open captions and quality menus") - .frame(maxWidth: 400) - .font(.caption) - .foregroundColor(.secondary) + Text("Press and hold remote button to open captions and quality menus") + .frame(maxWidth: 400) + .font(.caption) + .foregroundColor(.secondary) #endif } .frame(maxHeight: overlayHeight) @@ -117,9 +117,9 @@ struct ControlsOverlay: View { private var overlayHeight: Double { #if os(tvOS) - contentSize.height + 80.0 + contentSize.height + 80.0 #else - contentSize.height + contentSize.height #endif } @@ -160,26 +160,26 @@ struct ControlsOverlay: View { @ViewBuilder private var rateButton: some View { #if os(macOS) - ratePicker - .labelsHidden() - .frame(maxWidth: 100) - #elseif os(iOS) - Menu { ratePicker - } label: { - Text(player.rateLabel(player.currentRate)) - .foregroundColor(.primary) - .frame(width: 123) - } - .transaction { t in t.animation = .none } - .buttonStyle(.plain) - .foregroundColor(.primary) - .frame(width: 123, height: 40) - .modifier(ControlBackgroundModifier()) - .mask(RoundedRectangle(cornerRadius: 3)) + .labelsHidden() + .frame(maxWidth: 100) + #elseif os(iOS) + Menu { + ratePicker + } label: { + Text(player.rateLabel(player.currentRate)) + .foregroundColor(.primary) + .frame(width: 123) + } + .transaction { t in t.animation = .none } + .buttonStyle(.plain) + .foregroundColor(.primary) + .frame(width: 123, height: 40) + .modifier(ControlBackgroundModifier()) + .mask(RoundedRectangle(cornerRadius: 3)) #else - Text(player.rateLabel(player.currentRate)) - .frame(minWidth: 120) + Text(player.rateLabel(player.currentRate)) + .frame(minWidth: 120) #endif } @@ -241,50 +241,50 @@ struct ControlsOverlay: View { private var rateButtonsSpacing: Double { #if os(tvOS) - 10 + 10 #else - 8 + 8 #endif } @ViewBuilder private var qualityProfileButton: some View { #if os(macOS) - qualityProfilePicker - .labelsHidden() - .frame(maxWidth: 300) - #elseif os(iOS) - Menu { qualityProfilePicker - } label: { - Text(player.qualityProfileSelection?.description ?? "Automatic".localized()) - .frame(maxWidth: 240) - } - .transaction { t in t.animation = .none } - .buttonStyle(.plain) - .foregroundColor(.primary) - .frame(maxWidth: 240) - .frame(height: 40) - .modifier(ControlBackgroundModifier()) - .mask(RoundedRectangle(cornerRadius: 3)) - #else - ControlsOverlayButton(focusedField: $focusedField, field: .qualityProfile) { - Text(player.qualityProfileSelection?.description ?? "Automatic".localized()) - .lineLimit(1) - .frame(maxWidth: 320) - } - .contextMenu { - Button("Automatic") { player.qualityProfileSelection = nil } - - ForEach(qualityProfiles) { qualityProfile in - Button { - player.qualityProfileSelection = qualityProfile - } label: { - Text(qualityProfile.description) - } - - Button("Cancel", role: .cancel) {} + .labelsHidden() + .frame(maxWidth: 300) + #elseif os(iOS) + Menu { + qualityProfilePicker + } label: { + Text(player.qualityProfileSelection?.description ?? "Automatic".localized()) + .frame(maxWidth: 240) + } + .transaction { t in t.animation = .none } + .buttonStyle(.plain) + .foregroundColor(.primary) + .frame(maxWidth: 240) + .frame(height: 40) + .modifier(ControlBackgroundModifier()) + .mask(RoundedRectangle(cornerRadius: 3)) + #else + ControlsOverlayButton(focusedField: $focusedField, field: .qualityProfile) { + Text(player.qualityProfileSelection?.description ?? "Automatic".localized()) + .lineLimit(1) + .frame(maxWidth: 320) + } + .contextMenu { + Button("Automatic") { player.qualityProfileSelection = nil } + + ForEach(qualityProfiles) { qualityProfile in + Button { + player.qualityProfileSelection = qualityProfile + } label: { + Text(qualityProfile.description) + } + + Button("Cancel", role: .cancel) {} + } } - } #endif } @@ -300,91 +300,91 @@ struct ControlsOverlay: View { @ViewBuilder private var qualityButton: some View { #if os(macOS) - StreamControl() - .labelsHidden() - .frame(maxWidth: 300) - #elseif os(iOS) - Menu { StreamControl() - } label: { - Text(player.streamSelection?.resolutionAndFormat ?? "loading") - .frame(width: 140, height: 40) - .foregroundColor(.primary) - } - .transaction { t in t.animation = .none } - .buttonStyle(.plain) - .foregroundColor(.primary) - .frame(width: 240, height: 40) - .modifier(ControlBackgroundModifier()) - .mask(RoundedRectangle(cornerRadius: 3)) + .labelsHidden() + .frame(maxWidth: 300) + #elseif os(iOS) + Menu { + StreamControl() + } label: { + Text(player.streamSelection?.resolutionAndFormat ?? "loading") + .frame(width: 140, height: 40) + .foregroundColor(.primary) + } + .transaction { t in t.animation = .none } + .buttonStyle(.plain) + .foregroundColor(.primary) + .frame(width: 240, height: 40) + .modifier(ControlBackgroundModifier()) + .mask(RoundedRectangle(cornerRadius: 3)) #else - StreamControl(focusedField: $focusedField) + StreamControl(focusedField: $focusedField) #endif } @ViewBuilder private var captionsButton: some View { #if os(macOS) - captionsPicker - .labelsHidden() - .frame(maxWidth: 300) - #elseif os(iOS) - Menu { captionsPicker - } label: { - HStack(spacing: 4) { - Image(systemName: "text.bubble") - if let captions = captionsBinding.wrappedValue, - let language = LanguageCodes(rawValue: captions.code) + .labelsHidden() + .frame(maxWidth: 300) + #elseif os(iOS) + Menu { + captionsPicker + } label: { + HStack(spacing: 4) { + Image(systemName: "text.bubble") + if let captions = captionsBinding.wrappedValue, + let language = LanguageCodes(rawValue: captions.code) - { - Text("\(language.description.capitalized) (\(language.rawValue))") - .foregroundColor(.accentColor) - } else { - if captionsBinding.wrappedValue == nil { - Text("Not available") - } else { - Text("Disabled") + { + Text("\(language.description.capitalized) (\(language.rawValue))") .foregroundColor(.accentColor) + } else { + if captionsBinding.wrappedValue == nil { + Text("Not available") + } else { + Text("Disabled") + .foregroundColor(.accentColor) + } } } + .frame(width: 240) + .frame(height: 40) } + .transaction { t in t.animation = .none } + .buttonStyle(.plain) + .foregroundColor(.primary) .frame(width: 240) - .frame(height: 40) - } - .transaction { t in t.animation = .none } - .buttonStyle(.plain) - .foregroundColor(.primary) - .frame(width: 240) - .modifier(ControlBackgroundModifier()) - .mask(RoundedRectangle(cornerRadius: 3)) + .modifier(ControlBackgroundModifier()) + .mask(RoundedRectangle(cornerRadius: 3)) #else - ControlsOverlayButton(focusedField: $focusedField, field: .captions) { - HStack(spacing: 8) { - Image(systemName: "text.bubble") - if let captions = captionsBinding.wrappedValue, - let language = LanguageCodes(rawValue: captions.code) - { - Text("\(language.description.capitalized) (\(language.rawValue))") - .foregroundColor(.accentColor) - } else { - if captionsBinding.wrappedValue == nil { - Text("Not available") - } else { - Text("Disabled") + ControlsOverlayButton(focusedField: $focusedField, field: .captions) { + HStack(spacing: 8) { + Image(systemName: "text.bubble") + if let captions = captionsBinding.wrappedValue, + let language = LanguageCodes(rawValue: captions.code) + { + Text("\(language.description.capitalized) (\(language.rawValue))") .foregroundColor(.accentColor) + } else { + if captionsBinding.wrappedValue == nil { + Text("Not available") + } else { + Text("Disabled") + .foregroundColor(.accentColor) + } } } + .frame(maxWidth: 320) } - .frame(maxWidth: 320) - } - .contextMenu { - Button("Disabled") { captionsBinding.wrappedValue = nil } + .contextMenu { + Button("Disabled") { captionsBinding.wrappedValue = nil } - ForEach(player.currentVideo?.captions ?? []) { caption in - Button(caption.description) { captionsBinding.wrappedValue = caption } + ForEach(player.currentVideo?.captions ?? []) { caption in + Button(caption.description) { captionsBinding.wrappedValue = caption } + } + Button("Cancel", role: .cancel) {} } - Button("Cancel", role: .cancel) {} - } #endif } diff --git a/Shared/UserAgentManager.swift b/Shared/UserAgentManager.swift index 247965ba..f1b4640e 100644 --- a/Shared/UserAgentManager.swift +++ b/Shared/UserAgentManager.swift @@ -1,6 +1,6 @@ import Logging #if !os(tvOS) -import WebKit + import WebKit #endif final class UserAgentManager { @@ -8,7 +8,7 @@ final class UserAgentManager { private(set) var userAgent: String #if !os(tvOS) - private var webView: WKWebView? + private var webView: WKWebView? #endif private init() { @@ -19,19 +19,19 @@ final class UserAgentManager { userAgent = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)" #if !os(tvOS) - webView = WKWebView() - webView?.evaluateJavaScript("navigator.userAgent") { [weak self] result, _ in - if let userAgent = result as? String { - DispatchQueue.main.async { - self?.userAgent = userAgent - Logger(label: "stream.yattee.userAgentManager").info("User-Agent: \(userAgent)") + webView = WKWebView() + webView?.evaluateJavaScript("navigator.userAgent") { [weak self] result, _ in + if let userAgent = result as? String { + DispatchQueue.main.async { + self?.userAgent = userAgent + Logger(label: "stream.yattee.userAgentManager").info("User-Agent: \(userAgent)") + } + } else { + Logger(label: "stream.yattee.userAgentManager").warning("Failed to update User-Agent.") } - } else { - Logger(label: "stream.yattee.userAgentManager").warning("Failed to update User-Agent.") } - } #else - Logger(label: "stream.yattee.userAgentManager.tvOS").info("User-Agent: \(userAgent)") + Logger(label: "stream.yattee.userAgentManager.tvOS").info("User-Agent: \(userAgent)") #endif } } diff --git a/Shared/YatteeApp.swift b/Shared/YatteeApp.swift index 88e3a259..3c07a1d8 100644 --- a/Shared/YatteeApp.swift +++ b/Shared/YatteeApp.swift @@ -159,7 +159,7 @@ struct YatteeApp: App { #else SDImageCodersManager.shared.addCoder(SDImageAWebPCoder.shared) #endif - + SDWebImageManager.defaultImageCache = PINCache(name: "stream.yattee.app") if !Defaults[.lastAccountIsPublic] {