1
0
mirror of https://github.com/yattee/yattee.git synced 2024-12-13 13:50:32 +05:30

Details panels in controls

This commit is contained in:
Arkadiusz Fal 2022-07-10 19:51:46 +02:00
parent db46289813
commit f0b8e7f655
15 changed files with 203 additions and 123 deletions

View File

@ -0,0 +1,12 @@
import Foundation
import SwiftUI
extension Backport where Content: View {
@ViewBuilder func scrollContentBackground(_ visibility: Bool) -> some View {
if #available(iOS 16.0, macOS 13.0, tvOS 16.0, *) {
content.scrollContentBackground(visibility ? .visible : .hidden)
} else {
content
}
}
}

View File

@ -96,15 +96,12 @@ final class NavigationModel: ObservableObject {
player.hide()
navigation.presentingChannel = false
let recent = RecentItem(from: channel)
#if os(macOS)
Windows.main.open()
#else
player.hide()
#endif
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
recents.add(recent)
let recent = RecentItem(from: channel)
recents.add(RecentItem(from: channel))
if navigationStyle == .sidebar {
navigation.sidebarSectionChanged.toggle()
@ -115,7 +112,6 @@ final class NavigationModel: ObservableObject {
}
}
}
}
static func openChannelPlaylist(
_ playlist: ChannelPlaylist,

View File

@ -8,6 +8,7 @@ final class PlayerControlsModel: ObservableObject {
@Published var isPlaying = true
@Published var presentingControls = false { didSet { handlePresentationChange() } }
@Published var presentingControlsOverlay = false { didSet { handleOverlayPresentationChange() } }
@Published var presentingDetailsOverlay = false
@Published var timer: Timer?
#if os(tvOS)
@ -21,6 +22,7 @@ final class PlayerControlsModel: ObservableObject {
isPlaying: Bool = true,
presentingControls: Bool = false,
presentingControlsOverlay: Bool = false,
presentingDetailsOverlay: Bool = false,
timer: Timer? = nil,
player: PlayerModel? = nil
) {
@ -28,20 +30,22 @@ final class PlayerControlsModel: ObservableObject {
self.isPlaying = isPlaying
self.presentingControls = presentingControls
self.presentingControlsOverlay = presentingControlsOverlay
self.presentingDetailsOverlay = presentingDetailsOverlay
self.timer = timer
self.player = player
}
func handlePresentationChange() {
if presentingControls {
DispatchQueue.main.async { [weak self] in
self?.player?.backend.startControlsUpdates()
self?.resetTimer()
}
guard let self = self else { return }
if self.presentingControls {
self.player?.backend.startControlsUpdates()
self.resetTimer()
} else {
player?.backend.stopControlsUpdates()
timer?.invalidate()
timer = nil
self.player?.backend.stopControlsUpdates()
self.timer?.invalidate()
self.timer = nil
}
}
}
@ -54,6 +58,15 @@ final class PlayerControlsModel: ObservableObject {
}
}
var presentingOverlays: Bool {
presentingDetailsOverlay || presentingControlsOverlay
}
func hideOverlays() {
presentingDetailsOverlay = false
presentingControlsOverlay = false
}
func show() {
guard !(player?.currentItem.isNil ?? true) else {
return

View File

@ -98,7 +98,13 @@ final class PlayerModel: ObservableObject {
var context: NSManagedObjectContext = PersistenceController.shared.container.viewContext
var backgroundContext = PersistenceController.shared.container.newBackgroundContext()
@Published var playingFullScreen = false
#if os(tvOS)
static let fullScreenIsDefault = true
#else
static let fullScreenIsDefault = false
#endif
@Published var playingFullScreen = PlayerModel.fullScreenIsDefault
@Published var playingInPictureInPicture = false
var pipController: AVPictureInPictureController?
var pipDelegate = PiPDelegate()

View File

@ -142,7 +142,7 @@ struct ContentView: View {
.environmentObject(recents)
.environmentObject(subscriptions)
.environmentObject(thumbnailsModel)
.environment(\.navigationStyle, .sidebar)
.environment(\.navigationStyle, navigationStyle)
}
}

View File

@ -29,7 +29,7 @@ struct PlayerControls: View {
}
var body: some View {
ZStack(alignment: .topTrailing) {
ZStack(alignment: .topLeading) {
VStack {
ZStack(alignment: .center) {
OpeningStream()
@ -39,19 +39,20 @@ struct PlayerControls: View {
VStack(spacing: 4) {
buttonsBar
if let video = player.currentVideo, player.playingFullScreen {
VStack(alignment: .leading, spacing: 2) {
Text(video.title)
.font(.caption.bold())
Text(video.author)
.font(.caption)
.foregroundColor(.secondary)
HStack {
if !player.currentVideo.isNil, player.playingFullScreen {
Button {
withAnimation(Self.animation) {
model.presentingDetailsOverlay = true
}
.padding(4)
.modifier(ControlBackgroundModifier())
.clipShape(RoundedRectangle(cornerRadius: 2))
.frame(maxWidth: .infinity, alignment: .leading)
} label: {
ControlsBar(fullScreen: $model.presentingDetailsOverlay, presentingControls: false, detailsTogglePlayer: false, detailsToggleFullScreen: false)
.clipShape(RoundedRectangle(cornerRadius: 4))
.frame(maxWidth: 300, alignment: .leading)
}
.buttonStyle(.plain)
}
Spacer()
}
Spacer()
@ -69,9 +70,6 @@ struct PlayerControls: View {
.offset(y: -25)
.zIndex(1)
}
#if os(tvOS)
.offset(y: -50)
#endif
.frame(maxWidth: 500)
.padding(.bottom, 2)
}
@ -79,7 +77,7 @@ struct PlayerControls: View {
.padding(.top, 2)
.padding(.horizontal, 2)
}
.opacity(model.presentingControlsOverlay ? 1 : model.presentingControls ? 1 : 0)
.opacity(model.presentingOverlays ? 0 : model.presentingControls ? 1 : 0)
}
}
#if os(tvOS)
@ -99,11 +97,16 @@ struct PlayerControls: View {
ControlsOverlay()
.frame(height: overlayHeight)
.padding()
.modifier(ControlBackgroundModifier(enabled: true))
.modifier(ControlBackgroundModifier())
.clipShape(RoundedRectangle(cornerRadius: 4))
.offset(x: -2, y: 40)
.opacity(model.presentingControlsOverlay ? 1 : 0)
VideoDetailsOverlay()
.frame(maxWidth: detailsWidth, maxHeight: 450)
.modifier(ControlBackgroundModifier())
.clipShape(RoundedRectangle(cornerRadius: 4))
.opacity(model.presentingDetailsOverlay ? 1 : 0)
Button {
player.restoreLastSkippedSegment()
} label: {
@ -124,13 +127,18 @@ struct PlayerControls: View {
.offset(x: -2, y: -2)
}
.buttonStyle(.plain)
.opacity(model.presentingControls ? 0 : player.lastSkipped.isNil ? 0 : 1)
.opacity(model.presentingControls || model.presentingOverlays ? 0 : player.lastSkipped.isNil ? 0 : 1)
}
}
var overlayHeight: Double {
guard let player = player, player.playerSize.height.isFinite else { return 0 }
return [0, [player.playerSize.height - 80, 140].min()!].max()!
return [0, [player.playerSize.height - 40, 140].min()!].max()!
}
var detailsWidth: Double {
guard let player = player, player.playerSize.width.isFinite else { return 200 }
return [player.playerSize.width, 600].min()!
}
@ViewBuilder var controlsBackground: some View {

View File

@ -0,0 +1,25 @@
import Defaults
import SwiftUI
struct VideoDetailsOverlay: View {
@EnvironmentObject<PlayerControlsModel> private var controls
var body: some View {
VideoDetails(sidebarQueue: false, fullScreen: fullScreenBinding)
}
var fullScreenBinding: Binding<Bool> {
.init(get: {
controls.presentingDetailsOverlay
}, set: { newValue in
controls.presentingDetailsOverlay = newValue
})
}
}
struct VideoDetailsOverlay_Previews: PreviewProvider {
static var previews: some View {
VideoDetailsOverlay()
.injectFixtureEnvironmentObjects()
}
}

View File

@ -9,17 +9,7 @@ struct PlayerGestures: View {
gestureRectangle
.tapRecognizer(
tapSensitivity: 0.2,
singleTapAction: {
if model.presentingControlsOverlay {
model.presentingControls = true
model.resetTimer()
withAnimation(PlayerControls.animation) {
model.presentingControlsOverlay = false
}
} else {
model.toggle()
}
},
singleTapAction: { singleTapAction() },
doubleTapAction: {
player.backend.seek(relative: .secondsInDefaultTimescale(-10))
},
@ -31,17 +21,7 @@ struct PlayerGestures: View {
gestureRectangle
.tapRecognizer(
tapSensitivity: 0.2,
singleTapAction: {
if model.presentingControlsOverlay {
model.presentingControls = true
model.resetTimer()
withAnimation(PlayerControls.animation) {
model.presentingControlsOverlay = false
}
} else {
model.toggle()
}
},
singleTapAction: { singleTapAction() },
doubleTapAction: {
player.backend.togglePlay()
},
@ -53,17 +33,7 @@ struct PlayerGestures: View {
gestureRectangle
.tapRecognizer(
tapSensitivity: 0.2,
singleTapAction: {
if model.presentingControlsOverlay {
model.presentingControls = true
model.resetTimer()
withAnimation(PlayerControls.animation) {
model.presentingControlsOverlay = false
}
} else {
model.toggle()
}
},
singleTapAction: { singleTapAction() },
doubleTapAction: {
player.backend.seek(relative: .secondsInDefaultTimescale(10))
},
@ -74,6 +44,16 @@ struct PlayerGestures: View {
}
}
func singleTapAction() {
if model.presentingOverlays {
withAnimation(PlayerControls.animation) {
model.hideOverlays()
}
} else {
model.toggle()
}
}
var gestureRectangle: some View {
Color.clear
.contentShape(Rectangle())

View File

@ -26,7 +26,6 @@ struct PlayerQueueRow: View {
}
var body: some View {
Group {
Button {
player.prepareCurrentItemForHistory()
@ -54,7 +53,6 @@ struct PlayerQueueRow: View {
}
.buttonStyle(.plain)
}
}
private var watch: Watch? {
watchRequest.first

View File

@ -28,6 +28,7 @@ struct PlayerQueueView: View {
playedPreviously
}
}
.listRowBackground(Color.clear)
#if !os(iOS)
.padding(.vertical, 5)
.listRowInsets(EdgeInsets())
@ -38,6 +39,8 @@ struct PlayerQueueView: View {
.listStyle(.inset)
#elseif os(iOS)
.listStyle(.grouped)
.backport
.scrollContentBackground(false)
#else
.listStyle(.plain)
#endif

View File

@ -13,6 +13,7 @@ struct RelatedView: View {
Section(header: Text("Related")) {
ForEach(related) { video in
PlayerQueueRow(item: PlayerQueueItem(video))
.listRowBackground(Color.clear)
.contextMenu {
Section {
Button {
@ -53,6 +54,8 @@ struct RelatedView: View {
.listStyle(.inset)
#elseif os(iOS)
.listStyle(.grouped)
.backport
.scrollContentBackground(false)
#else
.listStyle(.plain)
#endif

View File

@ -108,7 +108,6 @@ struct VideoDetails: View {
page.update(.moveToLast)
}
}
.edgesIgnoringSafeArea(.horizontal)
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .topLeading)
}
@ -178,18 +177,14 @@ struct VideoDetails: View {
}
case .chapters:
ChaptersView()
.edgesIgnoringSafeArea(.horizontal)
case .queue:
PlayerQueueView(sidebarQueue: sidebarQueue, fullScreen: $fullScreen)
.edgesIgnoringSafeArea(.horizontal)
case .related:
RelatedView()
.edgesIgnoringSafeArea(.horizontal)
case .comments:
CommentsView(embedInScrollView: true)
.edgesIgnoringSafeArea(.horizontal)
}
}
.contentShape(Rectangle())
@ -209,16 +204,16 @@ struct VideoDetails: View {
VStack(alignment: .leading, spacing: 10) {
if !player.videoBeingOpened.isNil && (video.description.isNil || video.description!.isEmpty) {
VStack(alignment: .leading, spacing: 0) {
ForEach(1 ... Int.random(in: 3 ... 5), id: \.self) { _ in
Text(String(repeating: Video.fixture.description!, count: Int.random(in: 1 ... 4)))
Text(String(repeating: Video.fixture.description ?? "", count: Int.random(in: 1 ... 30)))
.redacted(reason: .placeholder)
}
}
} else if let description = video.description {
Group {
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, *) {
Text(description)
#if !os(tvOS)
.textSelection(.enabled)
#endif
} else {
Text(description)
}

View File

@ -119,6 +119,7 @@ struct VideoPlayerView: View {
}
viewVerticalOffset = Self.hiddenOffset
stopOrientationUpdates()
player.controls.hideOverlays()
}
}
#endif
@ -203,9 +204,9 @@ struct VideoPlayerView: View {
hoveringPlayer = hovering
hovering ? playerControls.show() : playerControls.hide()
}
#if !os(macOS)
.gesture(playerDragGesture)
#else
#if os(iOS)
.gesture(isPlayerDragGestureEnabled ? playerDragGesture : nil)
#elseif os(macOS)
.onAppear(perform: {
NSEvent.addLocalMonitorForEvents(matching: [.mouseMoved]) {
if !player.currentItem.isNil, hoveringPlayer {
@ -296,6 +297,9 @@ struct VideoPlayerView: View {
.onChange(of: proxy.size) { _ in
player.playerSize = proxy.size
}
.onChange(of: player.controls.presentingOverlays) { _ in
player.playerSize = proxy.size
}
})
#if os(iOS)
.padding(.top, player.playingFullScreen && verticalSizeClass == .regular ? 20 : 0)
@ -351,6 +355,10 @@ struct VideoPlayerView: View {
}
}
var isPlayerDragGestureEnabled: Bool {
!player.controls.presentingDetailsOverlay && !player.controls.presentingDetailsOverlay
}
var controlsTopPadding: Double {
guard fullScreenLayout else { return 0 }

View File

@ -24,6 +24,7 @@ struct ControlsBar: View {
var borderBottom = true
var detailsTogglePlayer = true
var detailsToggleFullScreen = false
var titleLineLimit = 2
var body: some View {
HStack(spacing: 0) {
@ -69,7 +70,9 @@ struct ControlsBar: View {
details
.contentShape(Rectangle())
}
#if !os(tvOS)
.keyboardShortcut("t")
#endif
} else {
details
}
@ -139,7 +142,9 @@ struct ControlsBar: View {
subscriptions.isSubscribing(video.channel.id)
{
Image(systemName: "star.circle.fill")
#if !os(tvOS)
.background(Color.background)
#endif
.clipShape(Circle())
.foregroundColor(.secondary)
}
@ -166,7 +171,9 @@ struct ControlsBar: View {
}
}
#if !os(tvOS)
ShareButton(contentItem: .init(video: model.currentVideo))
#endif
Section {
Button {
@ -215,12 +222,14 @@ struct ControlsBar: View {
}
}
VStack(alignment: .leading, spacing: 5) {
VStack(alignment: .leading, spacing: 0) {
Text(model.currentVideo?.title ?? "Not playing")
.font(.system(size: 14))
.fontWeight(.semibold)
.foregroundColor(model.currentVideo.isNil ? .secondary : .accentColor)
.lineLimit(1)
.fixedSize(horizontal: false, vertical: true)
.lineLimit(titleLineLimit)
.multilineTextAlignment(.leading)
if let video = model.currentVideo {
HStack(spacing: 2) {

View File

@ -714,6 +714,14 @@
37E70927271CDDAE00D34DDE /* OpenSettingsButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37E70926271CDDAE00D34DDE /* OpenSettingsButton.swift */; };
37E70928271CDDAE00D34DDE /* OpenSettingsButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37E70926271CDDAE00D34DDE /* OpenSettingsButton.swift */; };
37E70929271CDDAE00D34DDE /* OpenSettingsButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37E70926271CDDAE00D34DDE /* OpenSettingsButton.swift */; };
37E80F3C287B107F00561799 /* VideoDetailsOverlay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37E80F3B287B107F00561799 /* VideoDetailsOverlay.swift */; };
37E80F3D287B107F00561799 /* VideoDetailsOverlay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37E80F3B287B107F00561799 /* VideoDetailsOverlay.swift */; };
37E80F40287B472300561799 /* ScrollContentBackground+Backport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37E80F3F287B472300561799 /* ScrollContentBackground+Backport.swift */; };
37E80F43287B7AAF00561799 /* SwiftUIPager in Frameworks */ = {isa = PBXBuildFile; productRef = 37E80F42287B7AAF00561799 /* SwiftUIPager */; };
37E80F44287B7AB400561799 /* VideoDetails.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37B81AFE26D2CA3700675966 /* VideoDetails.swift */; };
37E80F45287B7AC000561799 /* ControlsBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 372CFD14285F2E2A00B0B54B /* ControlsBar.swift */; };
37E80F46287B7AEC00561799 /* PlayerQueueView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37CC3F4B270CFE1700608308 /* PlayerQueueView.swift */; };
37E80F47287B7B9400561799 /* VideoDetailsOverlay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37E80F3B287B107F00561799 /* VideoDetailsOverlay.swift */; };
37E8B0EC27B326C00024006F /* TimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37E8B0EB27B326C00024006F /* TimelineView.swift */; };
37E8B0ED27B326C00024006F /* TimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37E8B0EB27B326C00024006F /* TimelineView.swift */; };
37E8B0EE27B326C00024006F /* TimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37E8B0EB27B326C00024006F /* TimelineView.swift */; };
@ -1179,6 +1187,8 @@
37E64DD026D597EB00C71877 /* SubscriptionsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscriptionsModel.swift; sourceTree = "<group>"; };
37E70922271CD43000D34DDE /* WelcomeScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeScreen.swift; sourceTree = "<group>"; };
37E70926271CDDAE00D34DDE /* OpenSettingsButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenSettingsButton.swift; sourceTree = "<group>"; };
37E80F3B287B107F00561799 /* VideoDetailsOverlay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoDetailsOverlay.swift; sourceTree = "<group>"; };
37E80F3F287B472300561799 /* ScrollContentBackground+Backport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ScrollContentBackground+Backport.swift"; sourceTree = "<group>"; };
37E8B0EB27B326C00024006F /* TimelineView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimelineView.swift; sourceTree = "<group>"; };
37E8B0EF27B326F30024006F /* Comparable+Clamped.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Comparable+Clamped.swift"; sourceTree = "<group>"; };
37EAD86A267B9C5600D9E01B /* SponsorBlockAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SponsorBlockAPI.swift; sourceTree = "<group>"; };
@ -1369,6 +1379,7 @@
3772003A27E8EEBE00CB2475 /* CoreMedia.framework in Frameworks */,
372915E42687E33E00F5A35B /* Defaults in Frameworks */,
3772003B27E8EEC800CB2475 /* libbz2.tbd in Frameworks */,
37E80F43287B7AAF00561799 /* SwiftUIPager in Frameworks */,
37BADCA9269A570B009BE4FB /* Alamofire in Frameworks */,
37D4B19D2671817900C925CA /* SwiftyJSON in Frameworks */,
3797757D268922D100DD52A8 /* Siesta in Frameworks */,
@ -1437,6 +1448,7 @@
37F13B61285E43C000B137E4 /* ControlsOverlay.swift */,
37030FFE27B04DCC00ECDDAA /* PlayerControls.swift */,
37648B68286CF5F1003D330B /* TVControls.swift */,
37E80F3B287B107F00561799 /* VideoDetailsOverlay.swift */,
);
path = Controls;
sourceTree = "<group>";
@ -1554,10 +1566,11 @@
children = (
3722AEBD274DA401005EA4D6 /* Backport.swift */,
3722AEBB274DA396005EA4D6 /* Badge+Backport.swift */,
3722AEBF274DAEB8005EA4D6 /* Tint+Backport.swift */,
3727B74727872A500021C15E /* VisualEffectBlur-macOS.swift */,
3727B74927872A920021C15E /* VisualEffectBlur-iOS.swift */,
37136CAB286273060095C0CF /* PersistentSystemOverlays+Backport.swift */,
37E80F3F287B472300561799 /* ScrollContentBackground+Backport.swift */,
3722AEBF274DAEB8005EA4D6 /* Tint+Backport.swift */,
3727B74927872A920021C15E /* VisualEffectBlur-iOS.swift */,
3727B74727872A500021C15E /* VisualEffectBlur-macOS.swift */,
);
path = Backports;
sourceTree = "<group>";
@ -2311,6 +2324,7 @@
3765917D27237D2A009F956E /* PINCache */,
37CF8B8728535E6300B71E37 /* SDWebImage */,
372AA411286D06950000B1DC /* Repeat */,
37E80F42287B7AAF00561799 /* SwiftUIPager */,
);
productName = Yattee;
productReference = 37D4B158267164AE00C925CA /* Yattee.app */;
@ -2674,6 +2688,7 @@
378E50FF26FE8EEE00F49626 /* AccountsMenuView.swift in Sources */,
37169AA62729E2CC0011DE61 /* AccountsBridge.swift in Sources */,
37C7A1DA267CACF50010EAD6 /* TrendingCountry.swift in Sources */,
37E80F40287B472300561799 /* ScrollContentBackground+Backport.swift in Sources */,
3727B74A27872A920021C15E /* VisualEffectBlur-iOS.swift in Sources */,
37977583268922F600DD52A8 /* InvidiousAPI.swift in Sources */,
37130A5F277657300033018A /* PersistenceController.swift in Sources */,
@ -2836,6 +2851,7 @@
37BD07BB2698AB60003EBB87 /* AppSidebarNavigation.swift in Sources */,
37C0697A2725C09E00F7F6CB /* PlayerQueueItemBridge.swift in Sources */,
379B0253287A1CDF001015B5 /* OrientationTracker.swift in Sources */,
37E80F3C287B107F00561799 /* VideoDetailsOverlay.swift in Sources */,
370B79C9286279810045DB77 /* NSObject+Swizzle.swift in Sources */,
37D4B0E42671614900C925CA /* YatteeApp.swift in Sources */,
37C3A241272359900087A57A /* Double+Format.swift in Sources */,
@ -2886,6 +2902,7 @@
374C053C2724614F009BDDBE /* PlayerTVMenu.swift in Sources */,
377FC7DD267A081A00A6BBAF /* PopularView.swift in Sources */,
3784CDE327772EE40055BBF2 /* Watch.swift in Sources */,
37E80F3D287B107F00561799 /* VideoDetailsOverlay.swift in Sources */,
37DD9DBB2785D60300539416 /* FramePreferenceKey.swift in Sources */,
375DFB5926F9DA010013F468 /* InstancesModel.swift in Sources */,
3705B183267B4E4900704544 /* TrendingCategory.swift in Sources */,
@ -3159,6 +3176,7 @@
37732FF22703A26300F04329 /* AccountValidationStatus.swift in Sources */,
3756C2AC2861151C00E4B059 /* NetworkStateModel.swift in Sources */,
37A5DBCA285E371400CA4DD1 /* ControlBackgroundModifier.swift in Sources */,
37E80F46287B7AEC00561799 /* PlayerQueueView.swift in Sources */,
37C0698427260B2100F7F6CB /* ThumbnailsModel.swift in Sources */,
37666BAA27023AF000F869E5 /* AccountSelectionView.swift in Sources */,
3765788B2685471400D4EA09 /* Playlist.swift in Sources */,
@ -3168,6 +3186,8 @@
3752069B285E8DD300CA655F /* Chapter.swift in Sources */,
37B044B926F7AB9000E1419D /* SettingsView.swift in Sources */,
3743B86A27216D3600261544 /* ChannelCell.swift in Sources */,
37E80F47287B7B9400561799 /* VideoDetailsOverlay.swift in Sources */,
37E80F44287B7AB400561799 /* VideoDetails.swift in Sources */,
3751BA8527E6914F007B1A60 /* ReturnYouTubeDislikeAPI.swift in Sources */,
37030FFD27B0398000ECDDAA /* MPVClient.swift in Sources */,
37B767DD2677C3CA0098BAA8 /* PlayerModel.swift in Sources */,
@ -3180,6 +3200,7 @@
371B7E682759786B00D21217 /* Comment+Fixtures.swift in Sources */,
37BE0BD126A0E2D50092E2DB /* VideoPlayerView.swift in Sources */,
37AAF27E26737323007FC770 /* PopularView.swift in Sources */,
37E80F45287B7AC000561799 /* ControlsBar.swift in Sources */,
3743CA50270EFE3400E4D32B /* PlayerQueueRow.swift in Sources */,
376BE50827347B57009AD608 /* SettingsHeader.swift in Sources */,
37A9966026D6F9B9006E3224 /* FavoritesView.swift in Sources */,
@ -3900,7 +3921,7 @@
37D4B178267164B000C925CA /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 71;
@ -3909,7 +3930,6 @@
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = tvOS/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = Yattee;
INFOPLIST_KEY_CFBundleName = "Yattee (Apple TV)";
INFOPLIST_KEY_CFBundleVersion = 1;
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
@ -3938,7 +3958,7 @@
37D4B179267164B000C925CA /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 71;
@ -3947,7 +3967,6 @@
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = tvOS/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = Yattee;
INFOPLIST_KEY_CFBundleName = "Yattee (Apple TV)";
INFOPLIST_KEY_CFBundleVersion = 1;
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
@ -4470,6 +4489,11 @@
package = 37D4B19B2671817900C925CA /* XCRemoteSwiftPackageReference "SwiftyJSON" */;
productName = SwiftyJSON;
};
37E80F42287B7AAF00561799 /* SwiftUIPager */ = {
isa = XCSwiftPackageProductDependency;
package = 37A5DBC2285DFF5400CA4DD1 /* XCRemoteSwiftPackageReference "SwiftUIPager" */;
productName = SwiftUIPager;
};
37FB28452722054C00A57617 /* SDWebImageSwiftUI */ = {
isa = XCSwiftPackageProductDependency;
package = 37FB28442722054B00A57617 /* XCRemoteSwiftPackageReference "SDWebImageSwiftUI" */;