Improve open videos layouts

This commit is contained in:
Arkadiusz Fal 2022-11-11 18:50:13 +01:00
parent 6ca6a40aa1
commit 730ba1ea2e
9 changed files with 216 additions and 107 deletions

View File

@ -81,10 +81,13 @@ final class NavigationModel: ObservableObject {
@Published var alert = Alert(title: Text("Error")) @Published var alert = Alert(title: Text("Error"))
@Published var presentingAlert = false @Published var presentingAlert = false
@Published var presentingAlertInOpenVideos = false
#if os(macOS) #if os(macOS)
@Published var presentingAlertInVideoPlayer = false @Published var presentingAlertInVideoPlayer = false
#endif #endif
@Published var presentingFileImporter = false
static func openChannel( static func openChannel(
_ channel: Channel, _ channel: Channel,
player: PlayerModel, player: PlayerModel,

View File

@ -6,6 +6,7 @@ import Logging
#if canImport(UIKit) #if canImport(UIKit)
import UIKit import UIKit
#endif #endif
import SwiftUI
struct OpenVideosModel { struct OpenVideosModel {
enum PlaybackMode: String, CaseIterable { enum PlaybackMode: String, CaseIterable {
@ -62,11 +63,20 @@ struct OpenVideosModel {
return [] return []
} }
func openURLsFromClipboard(removeQueueItems: Bool = false, playbackMode: OpenVideosModel.PlaybackMode) { func openURLsFromClipboard(removeQueueItems: Bool = false, playbackMode: OpenVideosModel.PlaybackMode = .playNow) {
openURLs(urlsFromClipboard, removeQueueItems: removeQueueItems, playbackMode: playbackMode) if urlsFromClipboard.isEmpty {
NavigationModel.shared.alert = Alert(title: Text("Could not find any links to open in your clipboard"))
if NavigationModel.shared.presentingOpenVideos {
NavigationModel.shared.presentingAlertInOpenVideos = true
} else {
NavigationModel.shared.presentingAlert = true
}
} else {
openURLs(urlsFromClipboard, removeQueueItems: removeQueueItems, playbackMode: playbackMode)
}
} }
func openURLs(_ urls: [URL], removeQueueItems: Bool, playbackMode: OpenVideosModel.PlaybackMode) { func openURLs(_ urls: [URL], removeQueueItems: Bool = false, playbackMode: OpenVideosModel.PlaybackMode = .playNow) {
guard !urls.isEmpty else { guard !urls.isEmpty else {
return return
} }
@ -98,7 +108,6 @@ struct OpenVideosModel {
) )
if playbackMode == .playNow || playbackMode == .shuffleAll { if playbackMode == .playNow || playbackMode == .shuffleAll {
player.show()
#if os(iOS) #if os(iOS)
if player.presentingPlayer { if player.presentingPlayer {
player.advanceToNextItem() player.advanceToNextItem()
@ -108,6 +117,7 @@ struct OpenVideosModel {
#else #else
player.advanceToNextItem() player.advanceToNextItem()
#endif #endif
player.show()
} }
} }

View File

@ -10,24 +10,34 @@ struct HistoryView: View {
var body: some View { var body: some View {
LazyVStack { LazyVStack {
ForEach(visibleWatches, id: \.videoID) { watch in if visibleWatches.isEmpty {
PlayerQueueRow( VStack(alignment: .center, spacing: 20) {
item: PlayerQueueItem.from(watch, video: player.historyVideo(watch.videoID)), HStack {
history: true Image(systemName: "clock")
) Text("Playback history is empty")
.onAppear {
player.loadHistoryVideoDetails(watch.videoID) }.foregroundColor(.secondary)
} }
.contextMenu { } else {
VideoContextMenuView(video: player.historyVideo(watch.videoID) ?? watch.video) ForEach(visibleWatches, id: \.videoID) { watch in
PlayerQueueRow(
item: PlayerQueueItem.from(watch, video: player.historyVideo(watch.videoID)),
history: true
)
.onAppear {
player.loadHistoryVideoDetails(watch.videoID)
}
.contextMenu {
VideoContextMenuView(video: player.historyVideo(watch.videoID) ?? watch.video)
}
} }
} }
#if os(tvOS)
.padding(.horizontal, 40)
#else
.padding(.horizontal, 15)
#endif
} }
#if os(tvOS)
.padding(.horizontal, 40)
#else
.padding(.horizontal, 15)
#endif
} }
private var visibleWatches: [Watch] { private var visibleWatches: [Watch] {

View File

@ -24,6 +24,36 @@ struct HomeView: View {
var body: some View { var body: some View {
BrowserPlayerControls { BrowserPlayerControls {
ScrollView(.vertical, showsIndicators: false) { ScrollView(.vertical, showsIndicators: false) {
HStack {
#if os(tvOS)
OpenVideosButton(text: "Open Video", imageSystemName: "globe") {
NavigationModel.shared.presentingOpenVideos = true
}
.frame(maxWidth: 600)
#else
OpenVideosButton(text: "Files", imageSystemName: "folder") {
NavigationModel.shared.presentingFileImporter = true
}
OpenVideosButton(text: "Paste", imageSystemName: "doc.on.clipboard.fill") {
OpenVideosModel.shared.openURLsFromClipboard(playbackMode: .playNow)
}
OpenVideosButton(imageSystemName: "ellipsis") {
NavigationModel.shared.presentingOpenVideos = true
}
.frame(maxWidth: 40)
#endif
}
#if os(iOS)
.padding(.top, RefreshControl.navigationBarTitleDisplayMode == .inline ? 15 : 0)
#else
.padding(.top, 15)
#endif
#if os(tvOS)
.padding(.horizontal, 40)
#else
.padding(.horizontal, 15)
#endif
if !accounts.current.isNil { if !accounts.current.isNil {
#if os(tvOS) #if os(tvOS)
ForEach(Defaults[.favorites]) { item in ForEach(Defaults[.favorites]) { item in
@ -60,18 +90,7 @@ struct HomeView: View {
HistoryView(limit: homeHistoryItems) HistoryView(limit: homeHistoryItems)
} }
#if os(tvOS) #if !os(tvOS)
HStack {
Button {
navigation.presentingOpenVideos = true
} label: {
Label("Open Videos...", systemImage: "folder")
.padding(.horizontal, 20)
.padding(.vertical, 10)
}
.buttonStyle(.plain)
}
#else
Color.clear.padding(.bottom, 60) Color.clear.padding(.bottom, 60)
#endif #endif
} }

View File

@ -120,3 +120,10 @@ struct AppSidebarNavigation: View {
#endif #endif
} }
} }
struct AppSidebarNavigation_Preview: PreviewProvider {
static var previews: some View {
AppSidebarNavigation()
.injectFixtureEnvironmentObjects()
}
}

View File

@ -85,6 +85,32 @@ struct ContentView: View {
} }
) )
#if !os(tvOS) #if !os(tvOS)
.fileImporter(
isPresented: $navigation.presentingFileImporter,
allowedContentTypes: [.audiovisualContent],
allowsMultipleSelection: true
) { result in
do {
let selectedFiles = try result.get()
let urlsToOpen = selectedFiles.map { url in
if let bookmarkURL = URLBookmarkModel.shared.loadBookmark(url) {
return bookmarkURL
}
if url.startAccessingSecurityScopedResource() {
URLBookmarkModel.shared.saveBookmark(url)
}
return url
}
OpenVideosModel.shared.openURLs(urlsToOpen)
} catch {
NavigationModel.shared.presentAlert(title: "Could not open Files")
}
NavigationModel.shared.presentingOpenVideos = false
}
.onOpenURL { .onOpenURL {
OpenURLHandler( OpenURLHandler(
accounts: accounts, accounts: accounts,

View File

@ -0,0 +1,39 @@
import SwiftUI
struct OpenVideosButton: View {
var text: String?
var imageSystemName: String?
var action: () -> Void = {}
var body: some View {
Button(action: action) {
HStack {
if let imageSystemName {
Image(systemName: imageSystemName)
}
if let text {
Text(text ?? "")
.fontWeight(.bold)
}
}
.padding(.vertical, 10)
.frame(minHeight: 45)
.frame(maxWidth: .infinity)
.contentShape(Rectangle())
}
.foregroundColor(.accentColor)
.buttonStyle(.plain)
.background(buttonBackground)
}
var buttonBackground: some View {
RoundedRectangle(cornerRadius: 4)
.foregroundColor(Color.accentColor.opacity(0.33))
}
}
struct OpenVideosButton_Previews: PreviewProvider {
static var previews: some View {
OpenVideosButton(text: "Open Videos", imageSystemName: "play.circle.fill")
}
}

View File

@ -18,7 +18,7 @@ struct OpenVideosView: View {
var body: some View { var body: some View {
#if os(macOS) #if os(macOS)
openVideos openVideos
.frame(minWidth: 600, maxWidth: 800, minHeight: 250) .frame(minWidth: 600, maxWidth: 800, minHeight: 350, maxHeight: 500)
#else #else
NavigationView { NavigationView {
openVideos openVideos
@ -44,48 +44,45 @@ struct OpenVideosView: View {
VStack(alignment: .leading) { VStack(alignment: .leading) {
ZStack(alignment: .topLeading) { ZStack(alignment: .topLeading) {
#if os(tvOS) #if os(tvOS)
TextField("URLs to Open", text: $urlsToOpenText) TextField("URL to Open", text: $urlsToOpenText)
#else #else
TextEditor(text: $urlsToOpenText) TextEditor(text: $urlsToOpenText)
.padding(2) .padding(2)
.border(Color(white: 0.8), width: 1) .border(Color(white: 0.8), width: 1)
.frame(minHeight: 100, maxHeight: 200) .frame(minHeight: 100, maxHeight: 250)
#if !os(macOS) #if !os(macOS)
.keyboardType(.URL) .keyboardType(.URL)
#endif #endif
#endif #endif
} }
Text("Enter or paste URLs to open, one per line") Group {
.font(.caption2) #if os(tvOS)
.foregroundColor(.secondary) Text("Enter link to open")
#else
Menu { Text("Enter links to open, one per line")
Picker("Playback Mode", selection: $playbackMode) { #endif
ForEach(OpenVideosModel.PlaybackMode.allCases, id: \.rawValue) { mode in
Text(mode.description).tag(mode)
}
}
} label: {
Text(playbackMode.description)
} }
.transaction { t in t.disablesAnimations = true } .font(.caption2)
.labelsHidden() .foregroundColor(.secondary)
.padding(.bottom, 5)
.frame(maxWidth: .infinity, alignment: .center) playbackModeControl
Toggle(isOn: $removeQueueItems) { Toggle(isOn: $removeQueueItems) {
Text("Clear queue before opening") Text("Clear Queue before opening")
} }
.disabled(!playbackMode.allowsRemovingQueueItems) .disabled(!playbackMode.allowsRemovingQueueItems)
.padding(.bottom) .padding(.bottom)
HStack { HStack {
Group { Group {
#if os(tvOS)
Spacer()
#endif
openURLsButton openURLsButton
Spacer()
#if !os(tvOS) #if !os(tvOS)
Spacer()
openFromClipboardButton openFromClipboardButton
#endif #endif
@ -100,6 +97,7 @@ struct OpenVideosView: View {
Spacer() Spacer()
} }
.padding() .padding()
.alert(isPresented: $navigation.presentingAlertInOpenVideos) { navigation.alert }
#if !os(tvOS) #if !os(tvOS)
.fileImporter( .fileImporter(
isPresented: $presentingFileImporter, isPresented: $presentingFileImporter,
@ -122,7 +120,8 @@ struct OpenVideosView: View {
openURLs(selectedFiles) openURLs(selectedFiles)
} catch { } catch {
NavigationModel.shared.presentAlert(title: "Could not open Files") NavigationModel.shared.alert = Alert(title: Text("Could not open Files"))
NavigationModel.shared.presentingAlertInOpenVideos = true
} }
presentationMode.wrappedValue.dismiss() presentationMode.wrappedValue.dismiss()
@ -130,77 +129,64 @@ struct OpenVideosView: View {
#endif #endif
} }
var openURLsButton: some View { var playbackModeControl: some View {
Button { HStack {
openURLs(urlsToOpenFromText) #if !os(tvOS)
} label: { Text("Playback Mode")
HStack { Spacer()
Image(systemName: "network") #endif
Text("Open") #if os(iOS)
.fontWeight(.bold) Menu {
.padding(.vertical, 10) playbackModePicker
} } label: {
.frame(maxWidth: .infinity) Text(playbackMode.description)
.contentShape(Rectangle()) }
.padding(.horizontal, 20) #else
playbackModePicker
#if !os(tvOS)
.frame(maxWidth: 200)
#endif
#endif
}
.transaction { t in t.animation = .none }
.padding(.bottom, 5)
.frame(maxWidth: .infinity, alignment: .center)
}
var playbackModePicker: some View {
Picker("Playback Mode", selection: $playbackMode) {
ForEach(OpenVideosModel.PlaybackMode.allCases, id: \.rawValue) { mode in
Text(mode.description).tag(mode)
}
}
.labelsHidden()
}
var openURLsButton: some View {
OpenVideosButton(text: "Open", imageSystemName: "network") {
openURLs(urlsToOpenFromText)
} }
.foregroundColor(.accentColor)
.buttonStyle(.plain)
.background(buttonBackground)
.disabled(urlsToOpenFromText.isEmpty) .disabled(urlsToOpenFromText.isEmpty)
#if !os(tvOS) #if os(tvOS)
.frame(maxWidth: 600)
#else
.keyboardShortcut(.defaultAction) .keyboardShortcut(.defaultAction)
#endif #endif
} }
var openFromClipboardButton: some View { var openFromClipboardButton: some View {
Button { OpenVideosButton(text: "Paste", imageSystemName: "doc.on.clipboard.fill") {
OpenVideosModel.shared.openURLsFromClipboard( OpenVideosModel.shared.openURLsFromClipboard(
removeQueueItems: removeQueueItems, removeQueueItems: removeQueueItems,
playbackMode: playbackMode playbackMode: playbackMode
) )
} label: {
HStack {
Image(systemName: "doc.on.clipboard.fill")
Text("Paste")
.fontWeight(.bold)
.padding(.vertical, 10)
}
.frame(maxWidth: .infinity)
.contentShape(Rectangle())
.padding(.horizontal, 20)
} }
.foregroundColor(.accentColor)
.buttonStyle(.plain)
.background(buttonBackground)
#if !os(tvOS)
.keyboardShortcut(.defaultAction)
#endif
} }
var openFilesButton: some View { var openFilesButton: some View {
Button { OpenVideosButton(text: "Open Files", imageSystemName: "folder") {
presentingFileImporter = true presentingFileImporter = true
} label: {
HStack {
Image(systemName: "folder")
Text("Open Files")
.fontWeight(.bold)
.padding(.vertical, 10)
}
.frame(maxWidth: .infinity)
.contentShape(Rectangle())
.padding(.horizontal, 20)
} }
.foregroundColor(.accentColor)
.buttonStyle(.plain)
.background(buttonBackground)
}
var buttonBackground: some View {
RoundedRectangle(cornerRadius: 4)
.foregroundColor(Color.accentColor.opacity(0.33))
} }
var urlsToOpenFromText: [URL] { var urlsToOpenFromText: [URL] {
@ -217,6 +203,7 @@ struct OpenVideosView: View {
struct OpenVideosView_Previews: PreviewProvider { struct OpenVideosView_Previews: PreviewProvider {
static var previews: some View { static var previews: some View {
OpenVideosView() OpenVideosView()
.injectFixtureEnvironmentObjects()
#if os(iOS) #if os(iOS)
.navigationViewStyle(.stack) .navigationViewStyle(.stack)
#endif #endif

View File

@ -395,6 +395,9 @@
3761ABFF26F0F8DE00AA496F /* EnvironmentValues.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3761ABFC26F0F8DE00AA496F /* EnvironmentValues.swift */; }; 3761ABFF26F0F8DE00AA496F /* EnvironmentValues.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3761ABFC26F0F8DE00AA496F /* EnvironmentValues.swift */; };
3763495126DFF59D00B9A393 /* AppSidebarRecents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3763495026DFF59D00B9A393 /* AppSidebarRecents.swift */; }; 3763495126DFF59D00B9A393 /* AppSidebarRecents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3763495026DFF59D00B9A393 /* AppSidebarRecents.swift */; };
3763495226DFF59D00B9A393 /* AppSidebarRecents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3763495026DFF59D00B9A393 /* AppSidebarRecents.swift */; }; 3763495226DFF59D00B9A393 /* AppSidebarRecents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3763495026DFF59D00B9A393 /* AppSidebarRecents.swift */; };
37635FE4291EA6CF00C11E79 /* OpenVideosButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37635FE3291EA6CF00C11E79 /* OpenVideosButton.swift */; };
37635FE5291EA6CF00C11E79 /* OpenVideosButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37635FE3291EA6CF00C11E79 /* OpenVideosButton.swift */; };
37635FE6291EA6CF00C11E79 /* OpenVideosButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37635FE3291EA6CF00C11E79 /* OpenVideosButton.swift */; };
3763C989290C7A50004D3B5F /* OpenVideosView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3763C988290C7A50004D3B5F /* OpenVideosView.swift */; }; 3763C989290C7A50004D3B5F /* OpenVideosView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3763C988290C7A50004D3B5F /* OpenVideosView.swift */; };
3763C98A290C7A50004D3B5F /* OpenVideosView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3763C988290C7A50004D3B5F /* OpenVideosView.swift */; }; 3763C98A290C7A50004D3B5F /* OpenVideosView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3763C988290C7A50004D3B5F /* OpenVideosView.swift */; };
3763C98B290C7A50004D3B5F /* OpenVideosView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3763C988290C7A50004D3B5F /* OpenVideosView.swift */; }; 3763C98B290C7A50004D3B5F /* OpenVideosView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3763C988290C7A50004D3B5F /* OpenVideosView.swift */; };
@ -1138,6 +1141,7 @@
375F740F289DC35A00747050 /* PlayerBackendView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerBackendView.swift; sourceTree = "<group>"; }; 375F740F289DC35A00747050 /* PlayerBackendView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerBackendView.swift; sourceTree = "<group>"; };
3761ABFC26F0F8DE00AA496F /* EnvironmentValues.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnvironmentValues.swift; sourceTree = "<group>"; }; 3761ABFC26F0F8DE00AA496F /* EnvironmentValues.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnvironmentValues.swift; sourceTree = "<group>"; };
3763495026DFF59D00B9A393 /* AppSidebarRecents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSidebarRecents.swift; sourceTree = "<group>"; }; 3763495026DFF59D00B9A393 /* AppSidebarRecents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSidebarRecents.swift; sourceTree = "<group>"; };
37635FE3291EA6CF00C11E79 /* OpenVideosButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenVideosButton.swift; sourceTree = "<group>"; };
3763C988290C7A50004D3B5F /* OpenVideosView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenVideosView.swift; sourceTree = "<group>"; }; 3763C988290C7A50004D3B5F /* OpenVideosView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenVideosView.swift; sourceTree = "<group>"; };
37648B68286CF5F1003D330B /* TVControls.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TVControls.swift; sourceTree = "<group>"; }; 37648B68286CF5F1003D330B /* TVControls.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TVControls.swift; sourceTree = "<group>"; };
376527BA285F60F700102284 /* PlayerTimeModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerTimeModel.swift; sourceTree = "<group>"; }; 376527BA285F60F700102284 /* PlayerTimeModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerTimeModel.swift; sourceTree = "<group>"; };
@ -1688,6 +1692,8 @@
37152EE926EFEB95004FB96D /* LazyView.swift */, 37152EE926EFEB95004FB96D /* LazyView.swift */,
37030FF627B0347C00ECDDAA /* MPVPlayerView.swift */, 37030FF627B0347C00ECDDAA /* MPVPlayerView.swift */,
37E70926271CDDAE00D34DDE /* OpenSettingsButton.swift */, 37E70926271CDDAE00D34DDE /* OpenSettingsButton.swift */,
37635FE3291EA6CF00C11E79 /* OpenVideosButton.swift */,
3763C988290C7A50004D3B5F /* OpenVideosView.swift */,
37FEF11227EFD8580033912F /* PlaceholderCell.swift */, 37FEF11227EFD8580033912F /* PlaceholderCell.swift */,
3769C02D2779F18600DDB3EA /* PlaceholderProgressView.swift */, 3769C02D2779F18600DDB3EA /* PlaceholderProgressView.swift */,
37BA793A26DB8EE4002A0235 /* PlaylistVideosView.swift */, 37BA793A26DB8EE4002A0235 /* PlaylistVideosView.swift */,
@ -1698,7 +1704,6 @@
37AAF29F26741C97007FC770 /* SubscriptionsView.swift */, 37AAF29F26741C97007FC770 /* SubscriptionsView.swift */,
37B17D9F268A1F25006AEE9B /* VideoContextMenuView.swift */, 37B17D9F268A1F25006AEE9B /* VideoContextMenuView.swift */,
37E70922271CD43000D34DDE /* WelcomeScreen.swift */, 37E70922271CD43000D34DDE /* WelcomeScreen.swift */,
3763C988290C7A50004D3B5F /* OpenVideosView.swift */,
); );
path = Views; path = Views;
sourceTree = "<group>"; sourceTree = "<group>";
@ -2937,6 +2942,7 @@
374C053B2724614F009BDDBE /* PlayerTVMenu.swift in Sources */, 374C053B2724614F009BDDBE /* PlayerTVMenu.swift in Sources */,
37A9965A26D6F8CA006E3224 /* HorizontalCells.swift in Sources */, 37A9965A26D6F8CA006E3224 /* HorizontalCells.swift in Sources */,
37EBD8CA27AF26C200F1C24B /* MPVBackend.swift in Sources */, 37EBD8CA27AF26C200F1C24B /* MPVBackend.swift in Sources */,
37635FE4291EA6CF00C11E79 /* OpenVideosButton.swift in Sources */,
37D526DE2720AC4400ED2F5E /* VideosAPI.swift in Sources */, 37D526DE2720AC4400ED2F5E /* VideosAPI.swift in Sources */,
37484C2526FC83E000287258 /* InstanceForm.swift in Sources */, 37484C2526FC83E000287258 /* InstanceForm.swift in Sources */,
37DD9DBD2785D60300539416 /* ScrollViewMatcher.swift in Sources */, 37DD9DBD2785D60300539416 /* ScrollViewMatcher.swift in Sources */,
@ -3111,6 +3117,7 @@
37030FFC27B0398000ECDDAA /* MPVClient.swift in Sources */, 37030FFC27B0398000ECDDAA /* MPVClient.swift in Sources */,
3751B4B327836902000B7DF4 /* SearchPage.swift in Sources */, 3751B4B327836902000B7DF4 /* SearchPage.swift in Sources */,
3782B9532755667600990149 /* String+Format.swift in Sources */, 3782B9532755667600990149 /* String+Format.swift in Sources */,
37635FE5291EA6CF00C11E79 /* OpenVideosButton.swift in Sources */,
37E2EEAC270656EC00170416 /* BrowserPlayerControls.swift in Sources */, 37E2EEAC270656EC00170416 /* BrowserPlayerControls.swift in Sources */,
37BF662027308884008CCFB0 /* DropFavoriteOutside.swift in Sources */, 37BF662027308884008CCFB0 /* DropFavoriteOutside.swift in Sources */,
3776ADD7287381240078EBC4 /* Captions.swift in Sources */, 3776ADD7287381240078EBC4 /* Captions.swift in Sources */,
@ -3434,6 +3441,7 @@
37F7D82E289EB05F00E2B3D0 /* SettingsPickerModifier.swift in Sources */, 37F7D82E289EB05F00E2B3D0 /* SettingsPickerModifier.swift in Sources */,
374AB3DD28BCAF7E00DF56FB /* SeekType.swift in Sources */, 374AB3DD28BCAF7E00DF56FB /* SeekType.swift in Sources */,
374C053727242D9F009BDDBE /* SponsorBlockSettings.swift in Sources */, 374C053727242D9F009BDDBE /* SponsorBlockSettings.swift in Sources */,
37635FE6291EA6CF00C11E79 /* OpenVideosButton.swift in Sources */,
377ABC42286E4AD5009C986F /* InstancesManifest.swift in Sources */, 377ABC42286E4AD5009C986F /* InstancesManifest.swift in Sources */,
37C069802725C8D400F7F6CB /* CMTime+DefaultTimescale.swift in Sources */, 37C069802725C8D400F7F6CB /* CMTime+DefaultTimescale.swift in Sources */,
37EBD8CC27AF26C200F1C24B /* MPVBackend.swift in Sources */, 37EBD8CC27AF26C200F1C24B /* MPVBackend.swift in Sources */,