mirror of
https://github.com/yattee/yattee.git
synced 2024-12-22 13:33:42 +00:00
Use Swift 5.7 if-let style
This commit is contained in:
parent
8f96a7c5e0
commit
a086a0f440
@ -76,7 +76,7 @@ import SwiftUI
|
|||||||
let blurEffect = UIBlurEffect(style: blurStyle)
|
let blurEffect = UIBlurEffect(style: blurStyle)
|
||||||
blurView.effect = blurEffect
|
blurView.effect = blurEffect
|
||||||
|
|
||||||
if let vibrancyStyle = vibrancyStyle {
|
if let vibrancyStyle {
|
||||||
vibrancyView.effect = UIVibrancyEffect(blurEffect: blurEffect, style: vibrancyStyle)
|
vibrancyView.effect = UIVibrancyEffect(blurEffect: blurEffect, style: vibrancyStyle)
|
||||||
} else {
|
} else {
|
||||||
vibrancyView.effect = nil
|
vibrancyView.effect = nil
|
||||||
|
@ -59,7 +59,7 @@ struct Account: Defaults.Serializable, Hashable, Identifiable {
|
|||||||
var shortUsername: String {
|
var shortUsername: String {
|
||||||
let (username, _) = credentials
|
let (username, _) = credentials
|
||||||
|
|
||||||
guard let username = username,
|
guard let username,
|
||||||
username.count > 10
|
username.count > 10
|
||||||
else {
|
else {
|
||||||
return username ?? ""
|
return username ?? ""
|
||||||
@ -70,7 +70,7 @@ struct Account: Defaults.Serializable, Hashable, Identifiable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var description: String {
|
var description: String {
|
||||||
guard let name = name, !name.isEmpty else {
|
guard let name, !name.isEmpty else {
|
||||||
return shortUsername
|
return shortUsername
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ struct AccountsBridge: Defaults.Bridge {
|
|||||||
typealias Serializable = [String: String]
|
typealias Serializable = [String: String]
|
||||||
|
|
||||||
func serialize(_ value: Value?) -> Serializable? {
|
func serialize(_ value: Value?) -> Serializable? {
|
||||||
guard let value = value else {
|
guard let value else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -22,7 +22,7 @@ struct AccountsBridge: Defaults.Bridge {
|
|||||||
|
|
||||||
func deserialize(_ object: Serializable?) -> Value? {
|
func deserialize(_ object: Serializable?) -> Value? {
|
||||||
guard
|
guard
|
||||||
let object = object,
|
let object,
|
||||||
let id = object["id"],
|
let id = object["id"],
|
||||||
let instanceID = object["instanceID"],
|
let instanceID = object["instanceID"],
|
||||||
let url = object["apiURL"],
|
let url = object["apiURL"],
|
||||||
|
@ -6,7 +6,7 @@ struct InstancesBridge: Defaults.Bridge {
|
|||||||
typealias Serializable = [String: String]
|
typealias Serializable = [String: String]
|
||||||
|
|
||||||
func serialize(_ value: Value?) -> Serializable? {
|
func serialize(_ value: Value?) -> Serializable? {
|
||||||
guard let value = value else {
|
guard let value else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -22,7 +22,7 @@ struct InstancesBridge: Defaults.Bridge {
|
|||||||
|
|
||||||
func deserialize(_ object: Serializable?) -> Value? {
|
func deserialize(_ object: Serializable?) -> Value? {
|
||||||
guard
|
guard
|
||||||
let object = object,
|
let object,
|
||||||
let app = VideosApp(rawValue: object["app"] ?? ""),
|
let app = VideosApp(rawValue: object["app"] ?? ""),
|
||||||
let id = object["id"],
|
let id = object["id"],
|
||||||
let apiURL = object["apiURL"]
|
let apiURL = object["apiURL"]
|
||||||
|
@ -13,7 +13,7 @@ final class InvidiousAPI: Service, ObservableObject, VideosAPI {
|
|||||||
@Published var validInstance = true
|
@Published var validInstance = true
|
||||||
|
|
||||||
var signedIn: Bool {
|
var signedIn: Bool {
|
||||||
guard let account = account else { return false }
|
guard let account else { return false }
|
||||||
|
|
||||||
return !account.anonymous && !(account.token?.isEmpty ?? true)
|
return !account.anonymous && !(account.token?.isEmpty ?? true)
|
||||||
}
|
}
|
||||||
@ -182,8 +182,8 @@ final class InvidiousAPI: Service, ObservableObject, VideosAPI {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let username = username,
|
guard let username,
|
||||||
let password = password,
|
let password,
|
||||||
!username.isEmpty,
|
!username.isEmpty,
|
||||||
!password.isEmpty
|
!password.isEmpty
|
||||||
else {
|
else {
|
||||||
@ -406,7 +406,7 @@ final class InvidiousAPI: Service, ObservableObject, VideosAPI {
|
|||||||
resource = resource.withParam("duration", duration.rawValue)
|
resource = resource.withParam("duration", duration.rawValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let page = page {
|
if let page {
|
||||||
resource = resource.withParam("page", page)
|
resource = resource.withParam("page", page)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -420,7 +420,7 @@ final class InvidiousAPI: Service, ObservableObject, VideosAPI {
|
|||||||
|
|
||||||
func comments(_ id: Video.ID, page: String?) -> Resource? {
|
func comments(_ id: Video.ID, page: String?) -> Resource? {
|
||||||
let resource = resource(baseURL: account.url, path: basePathAppending("comments/\(id)"))
|
let resource = resource(baseURL: account.url, path: basePathAppending("comments/\(id)"))
|
||||||
guard let page = page else { return resource }
|
guard let page else { return resource }
|
||||||
|
|
||||||
return resource.withParam("continuation", page)
|
return resource.withParam("continuation", page)
|
||||||
}
|
}
|
||||||
|
@ -112,8 +112,8 @@ final class PipedAPI: Service, ObservableObject, VideosAPI {
|
|||||||
let (username, password) = AccountsModel.getCredentials(account)
|
let (username, password) = AccountsModel.getCredentials(account)
|
||||||
|
|
||||||
guard !account.anonymous,
|
guard !account.anonymous,
|
||||||
let username = username,
|
let username,
|
||||||
let password = password
|
let password
|
||||||
else {
|
else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -196,7 +196,7 @@ final class PipedAPI: Service, ObservableObject, VideosAPI {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var signedIn: Bool {
|
var signedIn: Bool {
|
||||||
guard let account = account else {
|
guard let account else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,11 +167,11 @@ extension VideosAPI {
|
|||||||
|
|
||||||
guard var startSeconds = seconds else { return nil }
|
guard var startSeconds = seconds else { return nil }
|
||||||
|
|
||||||
if let minutes = minutes {
|
if let minutes {
|
||||||
startSeconds += 60 * minutes
|
startSeconds += 60 * minutes
|
||||||
}
|
}
|
||||||
|
|
||||||
if let hours = hours {
|
if let hours {
|
||||||
startSeconds += 60 * 60 * hours
|
startSeconds += 60 * 60 * hours
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ extension PlayerModel {
|
|||||||
let results = try? backgroundContext.fetch(watchFetchRequest)
|
let results = try? backgroundContext.fetch(watchFetchRequest)
|
||||||
|
|
||||||
backgroundContext.perform { [weak self] in
|
backgroundContext.perform { [weak self] in
|
||||||
guard let self = self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ final class InstancesManifest: Service, ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func setPublicAccount(_ country: String?, accounts: AccountsModel, asCurrent: Bool = true) {
|
func setPublicAccount(_ country: String?, accounts: AccountsModel, asCurrent: Bool = true) {
|
||||||
guard let country = country else {
|
guard let country else {
|
||||||
accounts.publicAccount = nil
|
accounts.publicAccount = nil
|
||||||
if asCurrent {
|
if asCurrent {
|
||||||
accounts.configureAccount()
|
accounts.configureAccount()
|
||||||
@ -68,7 +68,7 @@ final class InstancesManifest: Service, ObservableObject {
|
|||||||
instance = countryInstances.randomElement() ?? regionInstances.randomElement()
|
instance = countryInstances.randomElement() ?? regionInstances.randomElement()
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let instance = instance else {
|
guard let instance else {
|
||||||
settings.presentAlert(title: "Could not change location", message: "No locations available at the moment")
|
settings.presentAlert(title: "Could not change location", message: "No locations available at the moment")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -180,7 +180,7 @@ final class NavigationModel: ObservableObject {
|
|||||||
let presentingPlayer = player.presentingPlayer
|
let presentingPlayer = player.presentingPlayer
|
||||||
player.hide()
|
player.hide()
|
||||||
|
|
||||||
if let searchQuery = searchQuery {
|
if let searchQuery {
|
||||||
let recent = RecentItem(from: searchQuery)
|
let recent = RecentItem(from: searchQuery)
|
||||||
recents.add(recent)
|
recents.add(recent)
|
||||||
|
|
||||||
|
@ -11,13 +11,13 @@ final class NetworkStateModel: ObservableObject {
|
|||||||
private let controlsOverlayModel = ControlOverlaysModel.shared
|
private let controlsOverlayModel = ControlOverlaysModel.shared
|
||||||
|
|
||||||
var osdVisible: Bool {
|
var osdVisible: Bool {
|
||||||
guard let player = player else { return false }
|
guard let player else { return false }
|
||||||
return player.isPlaying && ((player.activeBackend == .mpv && pausedForCache) || player.isSeeking) && bufferingState < 100.0
|
return player.isPlaying && ((player.activeBackend == .mpv && pausedForCache) || player.isSeeking) && bufferingState < 100.0
|
||||||
}
|
}
|
||||||
|
|
||||||
var fullStateText: String? {
|
var fullStateText: String? {
|
||||||
guard let bufferingStateText = bufferingStateText,
|
guard let bufferingStateText,
|
||||||
let cacheDurationText = cacheDurationText
|
let cacheDurationText
|
||||||
else {
|
else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -36,12 +36,12 @@ final class NetworkStateModel: ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var detailsAvailable: Bool {
|
var detailsAvailable: Bool {
|
||||||
guard let player = player else { return false }
|
guard let player else { return false }
|
||||||
return player.activeBackend.supportsNetworkStateBufferingDetails
|
return player.activeBackend.supportsNetworkStateBufferingDetails
|
||||||
}
|
}
|
||||||
|
|
||||||
var needsUpdates: Bool {
|
var needsUpdates: Bool {
|
||||||
if let player = player {
|
if let player {
|
||||||
return !player.currentItem.isNil && (pausedForCache || player.isSeeking || player.isLoadingVideo || controlsOverlayModel.presenting)
|
return !player.currentItem.isNil && (pausedForCache || player.isSeeking || player.isLoadingVideo || controlsOverlayModel.presenting)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,7 +211,7 @@ final class AVPlayerBackend: PlayerBackend {
|
|||||||
model: PlayerModel
|
model: PlayerModel
|
||||||
) {
|
) {
|
||||||
asset.loadValuesAsynchronously(forKeys: Self.assetKeysToLoad) { [weak self] in
|
asset.loadValuesAsynchronously(forKeys: Self.assetKeysToLoad) { [weak self] in
|
||||||
guard let self = self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
model.logger.info("loading \(type.rawValue) track")
|
model.logger.info("loading \(type.rawValue) track")
|
||||||
@ -285,7 +285,7 @@ final class AVPlayerBackend: PlayerBackend {
|
|||||||
guard let item = self.model.playerItem, self.isAutoplaying(item) else { return }
|
guard let item = self.model.playerItem, self.isAutoplaying(item) else { return }
|
||||||
|
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { [weak self] in
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { [weak self] in
|
||||||
guard let self = self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -361,7 +361,7 @@ final class AVPlayerBackend: PlayerBackend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func playerItem(_: Stream) -> AVPlayerItem? {
|
private func playerItem(_: Stream) -> AVPlayerItem? {
|
||||||
if let asset = asset {
|
if let asset {
|
||||||
return AVPlayerItem(asset: asset)
|
return AVPlayerItem(asset: asset)
|
||||||
} else {
|
} else {
|
||||||
return AVPlayerItem(asset: composition)
|
return AVPlayerItem(asset: composition)
|
||||||
@ -380,7 +380,7 @@ final class AVPlayerBackend: PlayerBackend {
|
|||||||
|
|
||||||
if let thumbnailURL = video.thumbnailURL(quality: .medium) {
|
if let thumbnailURL = video.thumbnailURL(quality: .medium) {
|
||||||
let task = URLSession.shared.dataTask(with: thumbnailURL) { [weak self] thumbnailData, _, _ in
|
let task = URLSession.shared.dataTask(with: thumbnailURL) { [weak self] thumbnailData, _, _ in
|
||||||
guard let thumbnailData = thumbnailData else { return }
|
guard let thumbnailData else { return }
|
||||||
|
|
||||||
let image = UIImage(data: thumbnailData)
|
let image = UIImage(data: thumbnailData)
|
||||||
if let pngData = image?.pngData() {
|
if let pngData = image?.pngData() {
|
||||||
@ -425,7 +425,7 @@ final class AVPlayerBackend: PlayerBackend {
|
|||||||
private func observePlayerItemStatus(_ item: AVPlayerItem) {
|
private func observePlayerItemStatus(_ item: AVPlayerItem) {
|
||||||
statusObservation?.invalidate()
|
statusObservation?.invalidate()
|
||||||
statusObservation = item.observe(\.status, options: [.old, .new]) { [weak self] playerItem, _ in
|
statusObservation = item.observe(\.status, options: [.old, .new]) { [weak self] playerItem, _ in
|
||||||
guard let self = self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -507,7 +507,7 @@ final class AVPlayerBackend: PlayerBackend {
|
|||||||
forInterval: interval,
|
forInterval: interval,
|
||||||
queue: .main
|
queue: .main
|
||||||
) { [weak self] _ in
|
) { [weak self] _ in
|
||||||
guard let self = self, self.model.activeBackend == .appleAVPlayer else {
|
guard let self, self.model.activeBackend == .appleAVPlayer else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -551,7 +551,7 @@ final class AVPlayerBackend: PlayerBackend {
|
|||||||
forInterval: interval,
|
forInterval: interval,
|
||||||
queue: .main
|
queue: .main
|
||||||
) { [weak self] _ in
|
) { [weak self] _ in
|
||||||
guard let self = self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -567,7 +567,7 @@ final class AVPlayerBackend: PlayerBackend {
|
|||||||
|
|
||||||
private func addPlayerTimeControlStatusObserver() {
|
private func addPlayerTimeControlStatusObserver() {
|
||||||
playerTimeControlStatusObserver = avPlayer.observe(\.timeControlStatus) { [weak self] player, _ in
|
playerTimeControlStatusObserver = avPlayer.observe(\.timeControlStatus) { [weak self] player, _ in
|
||||||
guard let self = self,
|
guard let self,
|
||||||
self.avPlayer == player,
|
self.avPlayer == player,
|
||||||
self.model.activeBackend == .appleAVPlayer
|
self.model.activeBackend == .appleAVPlayer
|
||||||
else {
|
else {
|
||||||
|
@ -22,7 +22,7 @@ final class MPVBackend: PlayerBackend {
|
|||||||
var stream: Stream?
|
var stream: Stream?
|
||||||
var video: Video?
|
var video: Video?
|
||||||
var captions: Captions? { didSet {
|
var captions: Captions? { didSet {
|
||||||
guard let captions = captions else {
|
guard let captions else {
|
||||||
client.removeSubs()
|
client.removeSubs()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -33,7 +33,7 @@ final class MPVBackend: PlayerBackend {
|
|||||||
var loadedVideo = false
|
var loadedVideo = false
|
||||||
var isLoadingVideo = true { didSet {
|
var isLoadingVideo = true { didSet {
|
||||||
DispatchQueue.main.async { [weak self] in
|
DispatchQueue.main.async { [weak self] in
|
||||||
guard let self = self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,7 +71,7 @@ final class MPVBackend: PlayerBackend {
|
|||||||
var isSeeking = false {
|
var isSeeking = false {
|
||||||
didSet {
|
didSet {
|
||||||
DispatchQueue.main.async { [weak self] in
|
DispatchQueue.main.async { [weak self] in
|
||||||
guard let self = self else { return }
|
guard let self else { return }
|
||||||
self.model.isSeeking = self.isSeeking
|
self.model.isSeeking = self.isSeeking
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -187,7 +187,7 @@ final class MPVBackend: PlayerBackend {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
DispatchQueue.main.async { [weak self] in
|
DispatchQueue.main.async { [weak self] in
|
||||||
guard let self = self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,14 +213,14 @@ final class MPVBackend: PlayerBackend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let replaceItem: (CMTime?) -> Void = { [weak self] time in
|
let replaceItem: (CMTime?) -> Void = { [weak self] time in
|
||||||
guard let self = self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
self.stop()
|
self.stop()
|
||||||
|
|
||||||
DispatchQueue.main.async { [weak self] in
|
DispatchQueue.main.async { [weak self] in
|
||||||
guard let self = self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -345,7 +345,7 @@ final class MPVBackend: PlayerBackend {
|
|||||||
model.updateNowPlayingInfo()
|
model.updateNowPlayingInfo()
|
||||||
|
|
||||||
handleSegmentsThrottle.execute {
|
handleSegmentsThrottle.execute {
|
||||||
if let currentTime = currentTime {
|
if let currentTime {
|
||||||
model.handleSegments(at: currentTime)
|
model.handleSegments(at: currentTime)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -453,7 +453,7 @@ final class MPVBackend: PlayerBackend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func updateNetworkState() {
|
func updateNetworkState() {
|
||||||
guard let client = client, let networkState = networkState else {
|
guard let client, let networkState else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ final class MPVClient: ObservableObject {
|
|||||||
|
|
||||||
func create(frame: CGRect? = nil) {
|
func create(frame: CGRect? = nil) {
|
||||||
#if !os(macOS)
|
#if !os(macOS)
|
||||||
if let frame = frame {
|
if let frame {
|
||||||
glView = MPVOGLView(frame: frame)
|
glView = MPVOGLView(frame: frame)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -134,7 +134,7 @@ final class MPVClient: ObservableObject {
|
|||||||
var args = [url.absoluteString]
|
var args = [url.absoluteString]
|
||||||
var options = [String]()
|
var options = [String]()
|
||||||
|
|
||||||
if let time = time {
|
if let time {
|
||||||
args.append("replace")
|
args.append("replace")
|
||||||
options.append("start=\(Int(time.seconds))")
|
options.append("start=\(Int(time.seconds))")
|
||||||
}
|
}
|
||||||
@ -268,7 +268,7 @@ final class MPVClient: ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DispatchQueue.main.async { [weak self] in
|
DispatchQueue.main.async { [weak self] in
|
||||||
guard let self = self, let model = self.backend.model else { return }
|
guard let self, let model = self.backend.model else { return }
|
||||||
UIView.animate(withDuration: 0.2, animations: {
|
UIView.animate(withDuration: 0.2, animations: {
|
||||||
let aspectRatio = self.aspectRatio > 0 && self.aspectRatio < VideoPlayerView.defaultAspectRatio ? self.aspectRatio : VideoPlayerView.defaultAspectRatio
|
let aspectRatio = self.aspectRatio > 0 && self.aspectRatio < VideoPlayerView.defaultAspectRatio ? self.aspectRatio : VideoPlayerView.defaultAspectRatio
|
||||||
let height = [model.playerSize.height, model.playerSize.width / aspectRatio].min()!
|
let height = [model.playerSize.height, model.playerSize.width / aspectRatio].min()!
|
||||||
|
@ -79,7 +79,7 @@ extension PlayerBackend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func seek(relative time: CMTime, seekType: SeekType, completionHandler: ((Bool) -> Void)? = nil) {
|
func seek(relative time: CMTime, seekType: SeekType, completionHandler: ((Bool) -> Void)? = nil) {
|
||||||
if let currentTime = currentTime, let duration = playerItemDuration {
|
if let currentTime, let duration = playerItemDuration {
|
||||||
let seekTime = min(max(0, currentTime.seconds + time.seconds), duration.seconds)
|
let seekTime = min(max(0, currentTime.seconds + time.seconds), duration.seconds)
|
||||||
model.seek.registerSeek(at: .secondsInDefaultTimescale(seekTime), type: seekType, restore: currentTime)
|
model.seek.registerSeek(at: .secondsInDefaultTimescale(seekTime), type: seekType, restore: currentTime)
|
||||||
seek(to: seekTime, seekType: seekType, completionHandler: completionHandler)
|
seek(to: seekTime, seekType: seekType, completionHandler: completionHandler)
|
||||||
|
@ -15,7 +15,7 @@ final class ControlOverlaysModel: ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func handlePresentationChange() {
|
private func handlePresentationChange() {
|
||||||
guard let player = player else { return }
|
guard let player else { return }
|
||||||
player.backend.setNeedsNetworkStateUpdates(presenting && Defaults[.showMPVPlaybackStats])
|
player.backend.setNeedsNetworkStateUpdates(presenting && Defaults[.showMPVPlaybackStats])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ final class PiPDelegate: NSObject, AVPictureInPictureControllerDelegate {
|
|||||||
func pictureInPictureControllerWillStartPictureInPicture(_: AVPictureInPictureController) {}
|
func pictureInPictureControllerWillStartPictureInPicture(_: AVPictureInPictureController) {}
|
||||||
|
|
||||||
func pictureInPictureControllerDidStartPictureInPicture(_: AVPictureInPictureController) {
|
func pictureInPictureControllerDidStartPictureInPicture(_: AVPictureInPictureController) {
|
||||||
guard let player = player else { return }
|
guard let player else { return }
|
||||||
|
|
||||||
player.playingInPictureInPicture = true
|
player.playingInPictureInPicture = true
|
||||||
player.avPlayerBackend.startPictureInPictureOnPlay = false
|
player.avPlayerBackend.startPictureInPictureOnPlay = false
|
||||||
@ -27,7 +27,7 @@ final class PiPDelegate: NSObject, AVPictureInPictureControllerDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func pictureInPictureControllerDidStopPictureInPicture(_: AVPictureInPictureController) {
|
func pictureInPictureControllerDidStopPictureInPicture(_: AVPictureInPictureController) {
|
||||||
guard let player = player else { return }
|
guard let player else { return }
|
||||||
|
|
||||||
player.playingInPictureInPicture = false
|
player.playingInPictureInPicture = false
|
||||||
player.controls.objectWillChange.send()
|
player.controls.objectWillChange.send()
|
||||||
|
@ -35,7 +35,7 @@ final class PlayerControlsModel: ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func handlePresentationChange() {
|
func handlePresentationChange() {
|
||||||
guard let player = player else { return }
|
guard let player else { return }
|
||||||
if presentingControls {
|
if presentingControls {
|
||||||
DispatchQueue.main.async(qos: .userInteractive) { [weak self] in
|
DispatchQueue.main.async(qos: .userInteractive) { [weak self] in
|
||||||
player.backend.startControlsUpdates()
|
player.backend.startControlsUpdates()
|
||||||
@ -82,7 +82,7 @@ final class PlayerControlsModel: ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func hide() {
|
func hide() {
|
||||||
guard let player = player,
|
guard let player,
|
||||||
!player.musicMode
|
!player.musicMode
|
||||||
else {
|
else {
|
||||||
return
|
return
|
||||||
@ -109,7 +109,7 @@ final class PlayerControlsModel: ObservableObject {
|
|||||||
func resetTimer() {
|
func resetTimer() {
|
||||||
removeTimer()
|
removeTimer()
|
||||||
|
|
||||||
guard let player = player, !player.musicMode else {
|
guard let player, !player.musicMode else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,7 +304,7 @@ final class PlayerModel: ObservableObject {
|
|||||||
|
|
||||||
var playingLive: Bool {
|
var playingLive: Bool {
|
||||||
guard live,
|
guard live,
|
||||||
let videoDuration = videoDuration,
|
let videoDuration,
|
||||||
let time = backend.currentTime?.seconds else { return false }
|
let time = backend.currentTime?.seconds else { return false }
|
||||||
|
|
||||||
return videoDuration - time < 30
|
return videoDuration - time < 30
|
||||||
@ -337,7 +337,7 @@ final class PlayerModel: ObservableObject {
|
|||||||
backend == .appleAVPlayer || !avPlayerBackend.startPictureInPictureOnPlay
|
backend == .appleAVPlayer || !avPlayerBackend.startPictureInPictureOnPlay
|
||||||
{
|
{
|
||||||
changeBackendHandler = { [weak self] in
|
changeBackendHandler = { [weak self] in
|
||||||
guard let self = self else { return }
|
guard let self else { return }
|
||||||
self.changeActiveBackend(from: self.activeBackend, to: backend)
|
self.changeActiveBackend(from: self.activeBackend, to: backend)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -499,7 +499,7 @@ final class PlayerModel: ObservableObject {
|
|||||||
fromBackend.pause()
|
fromBackend.pause()
|
||||||
}
|
}
|
||||||
|
|
||||||
guard var stream = stream, changingStream else {
|
guard var stream, changingStream else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -529,7 +529,7 @@ final class PlayerModel: ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in
|
||||||
guard let self = self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.upgradeToStream(stream, force: true)
|
self.upgradeToStream(stream, force: true)
|
||||||
@ -610,7 +610,7 @@ final class PlayerModel: ObservableObject {
|
|||||||
var pipPossible: Bool {
|
var pipPossible: Bool {
|
||||||
guard activeBackend == .appleAVPlayer else { return !transitioningToPiP }
|
guard activeBackend == .appleAVPlayer else { return !transitioningToPiP }
|
||||||
|
|
||||||
guard let pipController = pipController else { return false }
|
guard let pipController else { return false }
|
||||||
guard !pipController.isPictureInPictureActive else { return true }
|
guard !pipController.isPictureInPictureActive else { return true }
|
||||||
|
|
||||||
return pipController.isPictureInPicturePossible && !transitioningToPiP
|
return pipController.isPictureInPicturePossible && !transitioningToPiP
|
||||||
@ -644,7 +644,7 @@ final class PlayerModel: ObservableObject {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
DispatchQueue.main.async(qos: .background) { [weak self] in
|
DispatchQueue.main.async(qos: .background) { [weak self] in
|
||||||
guard let self = self else { return }
|
guard let self else { return }
|
||||||
if self.saveLastPlayed {
|
if self.saveLastPlayed {
|
||||||
self.lastPlayed = self.currentItem
|
self.lastPlayed = self.currentItem
|
||||||
}
|
}
|
||||||
@ -680,8 +680,8 @@ final class PlayerModel: ObservableObject {
|
|||||||
let results = try? context.fetch(watchFetchRequest)
|
let results = try? context.fetch(watchFetchRequest)
|
||||||
|
|
||||||
context.perform { [weak self] in
|
context.perform { [weak self] in
|
||||||
guard let self = self,
|
guard let self,
|
||||||
let results = results else { return }
|
let results else { return }
|
||||||
let resultsIds = results.map(\.videoID)
|
let resultsIds = results.map(\.videoID)
|
||||||
|
|
||||||
guard let autoplayVideo = related.filter({ !resultsIds.contains($0.videoID) }).randomElement() else {
|
guard let autoplayVideo = related.filter({ !resultsIds.contains($0.videoID) }).randomElement() else {
|
||||||
@ -693,7 +693,7 @@ final class PlayerModel: ObservableObject {
|
|||||||
self.autoplayItemSource = video
|
self.autoplayItemSource = video
|
||||||
|
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 3) { [weak self] in
|
DispatchQueue.main.asyncAfter(deadline: .now() + 3) { [weak self] in
|
||||||
guard let self = self else { return }
|
guard let self else { return }
|
||||||
self.playerAPI.loadDetails(item, completionHandler: { newItem in
|
self.playerAPI.loadDetails(item, completionHandler: { newItem in
|
||||||
guard newItem.videoID == self.autoplayItem?.videoID else { return }
|
guard newItem.videoID == self.autoplayItem?.videoID else { return }
|
||||||
self.autoplayItem = newItem
|
self.autoplayItem = newItem
|
||||||
@ -875,7 +875,7 @@ final class PlayerModel: ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let task = URLSession.shared.dataTask(with: thumbnailURL) { [weak self] thumbnailData, _, _ in
|
let task = URLSession.shared.dataTask(with: thumbnailURL) { [weak self] thumbnailData, _, _ in
|
||||||
guard let thumbnailData = thumbnailData else {
|
guard let thumbnailData else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -947,7 +947,7 @@ final class PlayerModel: ObservableObject {
|
|||||||
guard aspectRatio != backend.aspectRatio else { return }
|
guard aspectRatio != backend.aspectRatio else { return }
|
||||||
|
|
||||||
DispatchQueue.main.async { [weak self] in
|
DispatchQueue.main.async { [weak self] in
|
||||||
guard let self = self else { return }
|
guard let self else { return }
|
||||||
self.aspectRatio = self.backend.aspectRatio
|
self.aspectRatio = self.backend.aspectRatio
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -58,7 +58,7 @@ extension PlayerModel {
|
|||||||
preservedTime = currentItem.playbackTime
|
preservedTime = currentItem.playbackTime
|
||||||
|
|
||||||
DispatchQueue.main.async { [weak self] in
|
DispatchQueue.main.async { [weak self] in
|
||||||
guard let self = self else { return }
|
guard let self else { return }
|
||||||
guard let video = self.currentVideo else {
|
guard let video = self.currentVideo else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -122,7 +122,7 @@ extension PlayerModel {
|
|||||||
|
|
||||||
resetAutoplay()
|
resetAutoplay()
|
||||||
|
|
||||||
if let nextItem = nextItem {
|
if let nextItem {
|
||||||
advanceToItem(nextItem)
|
advanceToItem(nextItem)
|
||||||
} else {
|
} else {
|
||||||
advancing = false
|
advancing = false
|
||||||
@ -164,7 +164,7 @@ extension PlayerModel {
|
|||||||
|
|
||||||
func resetQueue() {
|
func resetQueue() {
|
||||||
DispatchQueue.main.async { [weak self] in
|
DispatchQueue.main.async { [weak self] in
|
||||||
guard let self = self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,7 +193,7 @@ extension PlayerModel {
|
|||||||
|
|
||||||
if loadDetails {
|
if loadDetails {
|
||||||
playerAPI.loadDetails(item, failureHandler: videoLoadFailureHandler) { [weak self] newItem in
|
playerAPI.loadDetails(item, failureHandler: videoLoadFailureHandler) { [weak self] newItem in
|
||||||
guard let self = self else { return }
|
guard let self else { return }
|
||||||
videoDetailsLoadHandler(newItem.video, newItem)
|
videoDetailsLoadHandler(newItem.video, newItem)
|
||||||
|
|
||||||
if play {
|
if play {
|
||||||
@ -239,7 +239,7 @@ extension PlayerModel {
|
|||||||
func restoreQueue() {
|
func restoreQueue() {
|
||||||
var restoredQueue = [PlayerQueueItem?]()
|
var restoredQueue = [PlayerQueueItem?]()
|
||||||
|
|
||||||
if let lastPlayed = lastPlayed,
|
if let lastPlayed,
|
||||||
!Defaults[.queue].contains(where: { $0.videoID == lastPlayed.videoID })
|
!Defaults[.queue].contains(where: { $0.videoID == lastPlayed.videoID })
|
||||||
{
|
{
|
||||||
restoredQueue.append(lastPlayed)
|
restoredQueue.append(lastPlayed)
|
||||||
|
@ -7,7 +7,7 @@ struct PlayerQueueItemBridge: Defaults.Bridge {
|
|||||||
typealias Serializable = [String: String]
|
typealias Serializable = [String: String]
|
||||||
|
|
||||||
func serialize(_ value: Value?) -> Serializable? {
|
func serialize(_ value: Value?) -> Serializable? {
|
||||||
guard let value = value else {
|
guard let value else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,7 +34,7 @@ struct PlayerQueueItemBridge: Defaults.Bridge {
|
|||||||
|
|
||||||
func deserialize(_ object: Serializable?) -> Value? {
|
func deserialize(_ object: Serializable?) -> Value? {
|
||||||
guard
|
guard
|
||||||
let object = object,
|
let object,
|
||||||
let videoID = object["videoID"]
|
let videoID = object["videoID"]
|
||||||
else {
|
else {
|
||||||
return nil
|
return nil
|
||||||
|
@ -37,7 +37,7 @@ extension PlayerModel {
|
|||||||
logger.error("segment end time is: \(segment.end) when player item duration is: \(duration.seconds)")
|
logger.error("segment end time is: \(segment.end) when player item duration is: \(duration.seconds)")
|
||||||
|
|
||||||
DispatchQueue.main.async { [weak self] in
|
DispatchQueue.main.async { [weak self] in
|
||||||
guard let self = self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ extension PlayerModel {
|
|||||||
func loadAvailableStreams(_ video: Video) {
|
func loadAvailableStreams(_ video: Video) {
|
||||||
availableStreams = []
|
availableStreams = []
|
||||||
|
|
||||||
guard let playerInstance = playerInstance else { return }
|
guard let playerInstance else { return }
|
||||||
|
|
||||||
logger.info("loading streams from \(playerInstance.description)")
|
logger.info("loading streams from \(playerInstance.description)")
|
||||||
fetchStreams(playerAPI.video(video.videoID), instance: playerInstance, video: video)
|
fetchStreams(playerAPI.video(video.videoID), instance: playerInstance, video: video)
|
||||||
|
@ -55,7 +55,7 @@ struct QualityProfile: Hashable, Identifiable, Defaults.Serializable {
|
|||||||
var formats: [Format]
|
var formats: [Format]
|
||||||
|
|
||||||
var description: String {
|
var description: String {
|
||||||
if let name = name, !name.isEmpty { return name }
|
if let name, !name.isEmpty { return name }
|
||||||
return "\(backend.label) - \(resolution.description) - \(formatsDescription)"
|
return "\(backend.label) - \(resolution.description) - \(formatsDescription)"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,7 +93,7 @@ struct QualityProfileBridge: Defaults.Bridge {
|
|||||||
typealias Serializable = [String: String]
|
typealias Serializable = [String: String]
|
||||||
|
|
||||||
func serialize(_ value: Value?) -> Serializable? {
|
func serialize(_ value: Value?) -> Serializable? {
|
||||||
guard let value = value else { return nil }
|
guard let value else { return nil }
|
||||||
|
|
||||||
return [
|
return [
|
||||||
"id": value.id,
|
"id": value.id,
|
||||||
@ -105,7 +105,7 @@ struct QualityProfileBridge: Defaults.Bridge {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func deserialize(_ object: Serializable?) -> Value? {
|
func deserialize(_ object: Serializable?) -> Value? {
|
||||||
guard let object = object,
|
guard let object,
|
||||||
let id = object["id"],
|
let id = object["id"],
|
||||||
let backend = PlayerBackendType(rawValue: object["backend"] ?? ""),
|
let backend = PlayerBackendType(rawValue: object["backend"] ?? ""),
|
||||||
let resolution = ResolutionSetting(rawValue: object["resolution"] ?? "")
|
let resolution = ResolutionSetting(rawValue: object["resolution"] ?? "")
|
||||||
|
@ -99,7 +99,7 @@ struct QualityProfilesModel {
|
|||||||
id = Defaults[.chargingNonCellularProfile]
|
id = Defaults[.chargingNonCellularProfile]
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
guard let id = id else { return nil }
|
guard let id else { return nil }
|
||||||
|
|
||||||
return find(id)
|
return find(id)
|
||||||
}
|
}
|
||||||
|
@ -137,7 +137,7 @@ struct RecentItemBridge: Defaults.Bridge {
|
|||||||
typealias Serializable = [String: String]
|
typealias Serializable = [String: String]
|
||||||
|
|
||||||
func serialize(_ value: Value?) -> Serializable? {
|
func serialize(_ value: Value?) -> Serializable? {
|
||||||
guard let value = value else {
|
guard let value else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,7 +150,7 @@ struct RecentItemBridge: Defaults.Bridge {
|
|||||||
|
|
||||||
func deserialize(_ object: Serializable?) -> Value? {
|
func deserialize(_ object: Serializable?) -> Value? {
|
||||||
guard
|
guard
|
||||||
let object = object,
|
let object,
|
||||||
let type = object["type"],
|
let type = object["type"],
|
||||||
let identifier = object["identifier"],
|
let identifier = object["identifier"],
|
||||||
let title = object["title"]
|
let title = object["title"]
|
||||||
|
@ -25,7 +25,7 @@ final class ReturnYouTubeDislikeAPI: ObservableObject {
|
|||||||
|
|
||||||
private func requestDislikes(completionHandler: @escaping (Int) -> Void = { _ in }) {
|
private func requestDislikes(completionHandler: @escaping (Int) -> Void = { _ in }) {
|
||||||
AF.request(votesURL).responseDecodable(of: JSON.self) { [weak self] response in
|
AF.request(votesURL).responseDecodable(of: JSON.self) { [weak self] response in
|
||||||
guard let self = self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ final class SeekModel: ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var gestureSeekDestinationTime: Double {
|
var gestureSeekDestinationTime: Double {
|
||||||
guard let gestureSeek = gestureSeek, let gestureStart = gestureStart else { return -1 }
|
guard let gestureSeek, let gestureStart else { return -1 }
|
||||||
return min(duration.seconds, max(0, gestureStart + gestureSeek))
|
return min(duration.seconds, max(0, gestureStart + gestureSeek))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@ final class SponsorBlockAPI: ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
AF.request(url, parameters: parameters(categories: categories)).responseDecodable(of: JSON.self) { [weak self] response in
|
AF.request(url, parameters: parameters(categories: categories)).responseDecodable(of: JSON.self) { [weak self] response in
|
||||||
guard let self = self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ extension Watch {
|
|||||||
watch = results?.first
|
watch = results?.first
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let watch = watch else { return }
|
guard let watch else { return }
|
||||||
|
|
||||||
watch.videoDuration = duration
|
watch.videoDuration = duration
|
||||||
watch.stoppedAt = duration
|
watch.stoppedAt = duration
|
||||||
@ -65,7 +65,7 @@ extension Watch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var watchedAtString: String? {
|
var watchedAtString: String? {
|
||||||
guard let watchedAt = watchedAt else {
|
guard let watchedAt else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,14 +11,14 @@ struct DropFavorite: DropDelegate {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let current = current else {
|
guard let current else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let from = favorites.firstIndex(of: current)
|
let from = favorites.firstIndex(of: current)
|
||||||
let to = favorites.firstIndex(of: item)
|
let to = favorites.firstIndex(of: item)
|
||||||
|
|
||||||
guard let from = from, let to = to else {
|
guard let from, let to else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ struct Buffering: View {
|
|||||||
|
|
||||||
Text(reason)
|
Text(reason)
|
||||||
.font(.system(size: playerControlsLayout.timeFontSize))
|
.font(.system(size: playerControlsLayout.timeFontSize))
|
||||||
if let state = state {
|
if let state {
|
||||||
Text(state)
|
Text(state)
|
||||||
.font(.system(size: playerControlsLayout.bufferingStateFontSize).monospacedDigit())
|
.font(.system(size: playerControlsLayout.bufferingStateFontSize).monospacedDigit())
|
||||||
}
|
}
|
||||||
|
@ -206,12 +206,12 @@ struct PlayerControls: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var detailsWidth: Double {
|
var detailsWidth: Double {
|
||||||
guard let player = player, player.playerSize.width.isFinite else { return 200 }
|
guard let player, player.playerSize.width.isFinite else { return 200 }
|
||||||
return [player.playerSize.width, 600].min()!
|
return [player.playerSize.width, 600].min()!
|
||||||
}
|
}
|
||||||
|
|
||||||
var detailsHeight: Double {
|
var detailsHeight: Double {
|
||||||
guard let player = player, player.playerSize.height.isFinite else { return 200 }
|
guard let player, player.playerSize.height.isFinite else { return 200 }
|
||||||
return [player.playerSize.height, 500].min()!
|
return [player.playerSize.height, 500].min()!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ final class MPVOGLView: GLKView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override func draw(_: CGRect) {
|
override func draw(_: CGRect) {
|
||||||
guard needsDrawing, let mpvGL = mpvGL else {
|
guard needsDrawing, let mpvGL else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ struct StreamControl: View {
|
|||||||
}
|
}
|
||||||
.transaction { t in t.animation = .none }
|
.transaction { t in t.animation = .none }
|
||||||
.onChange(of: player.streamSelection) { selection in
|
.onChange(of: player.streamSelection) { selection in
|
||||||
guard let selection = selection else { return }
|
guard let selection else { return }
|
||||||
player.upgradeToStream(selection)
|
player.upgradeToStream(selection)
|
||||||
player.controls.hideOverlays()
|
player.controls.hideOverlays()
|
||||||
}
|
}
|
||||||
|
@ -143,7 +143,7 @@ struct VideoDetails: View {
|
|||||||
|
|
||||||
var publishedDateSection: some View {
|
var publishedDateSection: some View {
|
||||||
Group {
|
Group {
|
||||||
if let video = video {
|
if let video {
|
||||||
HStack(spacing: 4) {
|
HStack(spacing: 4) {
|
||||||
if let published = video.publishedDate {
|
if let published = video.publishedDate {
|
||||||
Text(published)
|
Text(published)
|
||||||
@ -227,7 +227,7 @@ struct VideoDetails: View {
|
|||||||
|
|
||||||
var detailsPage: some View {
|
var detailsPage: some View {
|
||||||
VStack(alignment: .leading, spacing: 0) {
|
VStack(alignment: .leading, spacing: 0) {
|
||||||
if let video = video {
|
if let video {
|
||||||
VStack(spacing: 6) {
|
VStack(spacing: 6) {
|
||||||
videoProperties
|
videoProperties
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ struct VideoPlayerSizeModifier: ViewModifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var usedAspectRatio: Double {
|
var usedAspectRatio: Double {
|
||||||
guard let aspectRatio = aspectRatio, aspectRatio > 0, aspectRatio < VideoPlayerView.defaultAspectRatio else {
|
guard let aspectRatio, aspectRatio > 0, aspectRatio < VideoPlayerView.defaultAspectRatio else {
|
||||||
return VideoPlayerView.defaultAspectRatio
|
return VideoPlayerView.defaultAspectRatio
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ struct SearchTextField: View {
|
|||||||
.padding(.trailing, 15)
|
.padding(.trailing, 15)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if let favoriteItem = favoriteItem {
|
if let favoriteItem {
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
FavoriteButton(item: favoriteItem)
|
FavoriteButton(item: favoriteItem)
|
||||||
.id(favoriteItem.id)
|
.id(favoriteItem.id)
|
||||||
|
@ -117,7 +117,7 @@ struct SearchView: View {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
.onAppear {
|
.onAppear {
|
||||||
if let query = query {
|
if let query {
|
||||||
state.queryText = query.query
|
state.queryText = query.query
|
||||||
state.resetQuery(query)
|
state.resetQuery(query)
|
||||||
updateFavoriteItem()
|
updateFavoriteItem()
|
||||||
|
@ -18,7 +18,7 @@ struct AccountValidationStatus: View {
|
|||||||
|
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
Text(isValid ? "Connected successfully (\(app?.name ?? "Unknown"))" : "Connection failed")
|
Text(isValid ? "Connected successfully (\(app?.name ?? "Unknown"))" : "Connection failed")
|
||||||
if let error = error, !isValid {
|
if let error, !isValid {
|
||||||
Text(error)
|
Text(error)
|
||||||
.font(.caption2)
|
.font(.caption2)
|
||||||
.foregroundColor(.secondary)
|
.foregroundColor(.secondary)
|
||||||
|
@ -134,7 +134,7 @@ struct InstanceForm: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func submitForm() {
|
func submitForm() {
|
||||||
guard isValid, let app = app else {
|
guard isValid, let app else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ struct TrendingView: View {
|
|||||||
Spacer()
|
Spacer()
|
||||||
}
|
}
|
||||||
|
|
||||||
if let favoriteItem = favoriteItem {
|
if let favoriteItem {
|
||||||
FavoriteButton(item: favoriteItem, labelPadding: true)
|
FavoriteButton(item: favoriteItem, labelPadding: true)
|
||||||
.id(favoriteItem.id)
|
.id(favoriteItem.id)
|
||||||
.labelStyle(.iconOnly)
|
.labelStyle(.iconOnly)
|
||||||
@ -85,7 +85,7 @@ struct TrendingView: View {
|
|||||||
.toolbar {
|
.toolbar {
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
ToolbarItemGroup {
|
ToolbarItemGroup {
|
||||||
if let favoriteItem = favoriteItem {
|
if let favoriteItem {
|
||||||
FavoriteButton(item: favoriteItem)
|
FavoriteButton(item: favoriteItem)
|
||||||
.id(favoriteItem.id)
|
.id(favoriteItem.id)
|
||||||
}
|
}
|
||||||
@ -179,7 +179,7 @@ struct TrendingView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if os(tvOS)
|
#if os(tvOS)
|
||||||
if let favoriteItem = favoriteItem {
|
if let favoriteItem {
|
||||||
FavoriteButton(item: favoriteItem)
|
FavoriteButton(item: favoriteItem)
|
||||||
.id(favoriteItem.id)
|
.id(favoriteItem.id)
|
||||||
.labelStyle(.iconOnly)
|
.labelStyle(.iconOnly)
|
||||||
|
@ -55,7 +55,7 @@ struct URLParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var isYoutubeHost: Bool {
|
var isYoutubeHost: Bool {
|
||||||
guard let urlComponents = urlComponents else { return false }
|
guard let urlComponents else { return false }
|
||||||
|
|
||||||
return urlComponents.host == "youtube.com" || urlComponents.host == "www.youtube.com"
|
return urlComponents.host == "youtube.com" || urlComponents.host == "www.youtube.com"
|
||||||
}
|
}
|
||||||
@ -132,7 +132,7 @@ struct URLParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private var pathWithoutForwardSlash: String {
|
private var pathWithoutForwardSlash: String {
|
||||||
guard let urlComponents = urlComponents else { return "" }
|
guard let urlComponents else { return "" }
|
||||||
|
|
||||||
return String(urlComponents.path.dropFirst())
|
return String(urlComponents.path.dropFirst())
|
||||||
}
|
}
|
||||||
|
@ -280,7 +280,7 @@ struct VideoCell: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let time = time, !timeOnThumbnail {
|
if let time, !timeOnThumbnail {
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
HStack(spacing: 2) {
|
HStack(spacing: 2) {
|
||||||
@ -403,7 +403,7 @@ struct VideoCell: View {
|
|||||||
|
|
||||||
if timeOnThumbnail,
|
if timeOnThumbnail,
|
||||||
!video.live,
|
!video.live,
|
||||||
let time = time
|
let time
|
||||||
{
|
{
|
||||||
DetailBadge(text: time, style: .prominent)
|
DetailBadge(text: time, style: .prominent)
|
||||||
}
|
}
|
||||||
@ -429,7 +429,7 @@ struct VideoCell: View {
|
|||||||
}
|
}
|
||||||
.retryOnAppear(true)
|
.retryOnAppear(true)
|
||||||
.onFailure { _ in
|
.onFailure { _ in
|
||||||
guard let url = url else { return }
|
guard let url else { return }
|
||||||
thumbnails.insertUnloadable(url)
|
thumbnails.insertUnloadable(url)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ struct ControlsBar: View {
|
|||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
.background(
|
.background(
|
||||||
EmptyView().sheet(isPresented: $presentingShareSheet) {
|
EmptyView().sheet(isPresented: $presentingShareSheet) {
|
||||||
if let shareURL = shareURL {
|
if let shareURL {
|
||||||
ShareSheet(activityItems: [shareURL])
|
ShareSheet(activityItems: [shareURL])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ struct VideoContextMenuView: View {
|
|||||||
@ViewBuilder var contextMenu: some View {
|
@ViewBuilder var contextMenu: some View {
|
||||||
if saveHistory {
|
if saveHistory {
|
||||||
Section {
|
Section {
|
||||||
if let watchedAtString = watchedAtString {
|
if let watchedAtString {
|
||||||
Text(watchedAtString)
|
Text(watchedAtString)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,7 +115,7 @@ struct VideoContextMenuView: View {
|
|||||||
return "Watching now".localized()
|
return "Watching now".localized()
|
||||||
}
|
}
|
||||||
|
|
||||||
if let watch = watch, let watchedAtString = watch.watchedAtString {
|
if let watch, let watchedAtString = watch.watchedAtString {
|
||||||
if watchedAtString == "in 0 seconds" {
|
if watchedAtString == "in 0 seconds" {
|
||||||
return "Just watched".localized()
|
return "Just watched".localized()
|
||||||
}
|
}
|
||||||
@ -144,7 +144,7 @@ struct VideoContextMenuView: View {
|
|||||||
|
|
||||||
var removeFromHistoryButton: some View {
|
var removeFromHistoryButton: some View {
|
||||||
Button {
|
Button {
|
||||||
guard let watch = watch else {
|
guard let watch else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ import UIKit
|
|||||||
extension UIView {
|
extension UIView {
|
||||||
/// Returs frame in screen coordinates.
|
/// Returs frame in screen coordinates.
|
||||||
var globalFrame: CGRect {
|
var globalFrame: CGRect {
|
||||||
if let window = window {
|
if let window {
|
||||||
return convert(bounds, to: window.screen.coordinateSpace)
|
return convert(bounds, to: window.screen.coordinateSpace)
|
||||||
} else {
|
} else {
|
||||||
return .zero
|
return .zero
|
||||||
|
@ -31,7 +31,7 @@ final class ScrollViewMatcherViewController: UIViewController {
|
|||||||
private var scrollView: UIScrollView? {
|
private var scrollView: UIScrollView? {
|
||||||
didSet {
|
didSet {
|
||||||
if oldValue != scrollView,
|
if oldValue != scrollView,
|
||||||
let scrollView = scrollView
|
let scrollView
|
||||||
{
|
{
|
||||||
onMatch(scrollView)
|
onMatch(scrollView)
|
||||||
}
|
}
|
||||||
@ -70,7 +70,7 @@ final class ScrollViewMatcherViewController: UIViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func matchUsingGeometry() {
|
func matchUsingGeometry() {
|
||||||
if let parent = parent {
|
if let parent {
|
||||||
if let scrollViewsInHierarchy: [UIScrollView] = parent.view.viewsInHierarchy() {
|
if let scrollViewsInHierarchy: [UIScrollView] = parent.view.viewsInHierarchy() {
|
||||||
// Return first match if only a single scroll view is found in the hierarchy.
|
// Return first match if only a single scroll view is found in the hierarchy.
|
||||||
if scrollViewsInHierarchy.count == 1,
|
if scrollViewsInHierarchy.count == 1,
|
||||||
|
@ -21,7 +21,7 @@ struct Orientation {
|
|||||||
static func lockOrientation(_ orientation: UIInterfaceOrientationMask, andRotateTo rotateOrientation: UIInterfaceOrientation? = nil) {
|
static func lockOrientation(_ orientation: UIInterfaceOrientationMask, andRotateTo rotateOrientation: UIInterfaceOrientation? = nil) {
|
||||||
lockOrientation(orientation)
|
lockOrientation(orientation)
|
||||||
|
|
||||||
guard let rotateOrientation = rotateOrientation else {
|
guard let rotateOrientation else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ public class OrientationTracker {
|
|||||||
public func startDeviceOrientationTracking() {
|
public func startDeviceOrientationTracking() {
|
||||||
motionManager.startAccelerometerUpdates(to: queue) { accelerometerData, error in
|
motionManager.startAccelerometerUpdates(to: queue) { accelerometerData, error in
|
||||||
guard error == nil else { return }
|
guard error == nil else { return }
|
||||||
guard let accelerometerData = accelerometerData else { return }
|
guard let accelerometerData else { return }
|
||||||
|
|
||||||
let newDeviceOrientation = self.deviceOrientation(forAccelerometerData: accelerometerData)
|
let newDeviceOrientation = self.deviceOrientation(forAccelerometerData: accelerometerData)
|
||||||
guard newDeviceOrientation != self.currentDeviceOrientation else { return }
|
guard newDeviceOrientation != self.currentDeviceOrientation else { return }
|
||||||
|
Loading…
Reference in New Issue
Block a user