diff --git a/Pearvidious.xcodeproj/project.pbxproj b/Pearvidious.xcodeproj/project.pbxproj index 2771db4f..c9d15a59 100644 --- a/Pearvidious.xcodeproj/project.pbxproj +++ b/Pearvidious.xcodeproj/project.pbxproj @@ -192,6 +192,9 @@ 376BE50727347B57009AD608 /* SettingsHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 376BE50627347B57009AD608 /* SettingsHeader.swift */; }; 376BE50827347B57009AD608 /* SettingsHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 376BE50627347B57009AD608 /* SettingsHeader.swift */; }; 376BE50927347B5F009AD608 /* SettingsHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 376BE50627347B57009AD608 /* SettingsHeader.swift */; }; + 376BE50B27349108009AD608 /* BrowsingSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 376BE50A27349108009AD608 /* BrowsingSettings.swift */; }; + 376BE50C27349108009AD608 /* BrowsingSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 376BE50A27349108009AD608 /* BrowsingSettings.swift */; }; + 376BE50D27349108009AD608 /* BrowsingSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 376BE50A27349108009AD608 /* BrowsingSettings.swift */; }; 376CD21626FBE18D001E1AC1 /* Instance+Fixtures.swift in Sources */ = {isa = PBXBuildFile; fileRef = 376CD21526FBE18D001E1AC1 /* Instance+Fixtures.swift */; }; 376CD21726FBE18D001E1AC1 /* Instance+Fixtures.swift in Sources */ = {isa = PBXBuildFile; fileRef = 376CD21526FBE18D001E1AC1 /* Instance+Fixtures.swift */; }; 376CD21826FBE18D001E1AC1 /* Instance+Fixtures.swift in Sources */ = {isa = PBXBuildFile; fileRef = 376CD21526FBE18D001E1AC1 /* Instance+Fixtures.swift */; }; @@ -571,6 +574,7 @@ 376A33E32720CB35000C1D6B /* Account.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Account.swift; sourceTree = ""; }; 376B2E0626F920D600B1D64D /* SignInRequiredView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInRequiredView.swift; sourceTree = ""; }; 376BE50627347B57009AD608 /* SettingsHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsHeader.swift; sourceTree = ""; }; + 376BE50A27349108009AD608 /* BrowsingSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowsingSettings.swift; sourceTree = ""; }; 376CD21526FBE18D001E1AC1 /* Instance+Fixtures.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Instance+Fixtures.swift"; sourceTree = ""; }; 37732FEF2703A26300F04329 /* AccountValidationStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountValidationStatus.swift; sourceTree = ""; }; 37732FF32703D32400F04329 /* Sidebar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sidebar.swift; sourceTree = ""; }; @@ -914,6 +918,7 @@ 37484C2826FC83FF00287258 /* AccountForm.swift */, 37484C2C26FC844700287258 /* AccountsSettings.swift */, 37732FEF2703A26300F04329 /* AccountValidationStatus.swift */, + 376BE50A27349108009AD608 /* BrowsingSettings.swift */, 37484C2426FC83E000287258 /* InstanceForm.swift */, 37484C1C26FC83A400287258 /* InstancesSettings.swift */, 37484C1826FC837400287258 /* PlaybackSettings.swift */, @@ -1752,6 +1757,7 @@ 373CFACB26966264003CB2C6 /* SearchQuery.swift in Sources */, 37141673267A8E10006CA35D /* Country.swift in Sources */, 3748186E26A769D60084E870 /* DetailBadge.swift in Sources */, + 376BE50B27349108009AD608 /* BrowsingSettings.swift in Sources */, 37AAF2A026741C97007FC770 /* SubscriptionsView.swift in Sources */, 37599F30272B42810087F250 /* FavoriteItem.swift in Sources */, 373197D92732015300EF734F /* RelatedView.swift in Sources */, @@ -1882,6 +1888,7 @@ 37BA794C26DC30EC002A0235 /* AppSidebarPlaylists.swift in Sources */, 37CC3F46270CE30600608308 /* PlayerQueueItem.swift in Sources */, 3700155C271B0D4D0049C794 /* PipedAPI.swift in Sources */, + 376BE50C27349108009AD608 /* BrowsingSettings.swift in Sources */, 37D4B19826717E1500C925CA /* Video.swift in Sources */, 37599F31272B42810087F250 /* FavoriteItem.swift in Sources */, 3730F75A2733481E00F385FC /* RelatedView.swift in Sources */, @@ -1956,6 +1963,7 @@ 3788AC2926F6840700F6BAA9 /* FavoriteItemView.swift in Sources */, 37319F0727103F94004ECCD0 /* PlayerQueue.swift in Sources */, 37E70925271CD43000D34DDE /* WelcomeScreen.swift in Sources */, + 376BE50D27349108009AD608 /* BrowsingSettings.swift in Sources */, 37DD87C9271C9CFE0027CBF9 /* PlayerStreams.swift in Sources */, 37FFC442272734C3009FFD26 /* Throttle.swift in Sources */, 375168D82700FDB9008F96A6 /* Debounce.swift in Sources */, diff --git a/Shared/Defaults.swift b/Shared/Defaults.swift index a18e7ca2..c9ed85ea 100644 --- a/Shared/Defaults.swift +++ b/Shared/Defaults.swift @@ -51,6 +51,9 @@ extension Defaults.Keys { .init(section: .trending("US", nil)) ]) + static let channelOnThumbnail = Key("channelOnThumbnail", default: true) + static let timeOnThumbnail = Key("timeOnThumbnail", default: true) + static let quality = Key("quality", default: .hd720pFirstThenBest) static let playerSidebar = Key("playerSidebar", default: PlayerSidebarSetting.defaultValue) static let playerInstanceID = Key("playerInstance") diff --git a/Shared/Settings/BrowsingSettings.swift b/Shared/Settings/BrowsingSettings.swift new file mode 100644 index 00000000..0312378e --- /dev/null +++ b/Shared/Settings/BrowsingSettings.swift @@ -0,0 +1,26 @@ +import Defaults +import SwiftUI + +struct BrowsingSettings: View { + @Default(.channelOnThumbnail) private var channelOnThumbnail + @Default(.timeOnThumbnail) private var timeOnThumbnail + + var body: some View { + Section(header: SettingsHeader(text: "Thumbnails")) { + Toggle("Display channel names on thumbnails", isOn: $channelOnThumbnail) + Toggle("Display video length on thumbnails", isOn: $timeOnThumbnail) + } + .frame(minWidth: 0, maxWidth: .infinity, alignment: .leading) + + #if os(macOS) + Spacer() + #endif + } +} + +struct BrowsingSettings_Previews: PreviewProvider { + static var previews: some View { + BrowsingSettings() + .injectFixtureEnvironmentObjects() + } +} diff --git a/Shared/Settings/SettingsView.swift b/Shared/Settings/SettingsView.swift index 1da71af1..5e6700b6 100644 --- a/Shared/Settings/SettingsView.swift +++ b/Shared/Settings/SettingsView.swift @@ -5,7 +5,7 @@ import SwiftUI struct SettingsView: View { #if os(macOS) private enum Tabs: Hashable { - case instances, playback, services + case instances, browsing, playback, services } #endif @@ -24,6 +24,14 @@ struct SettingsView: View { } .tag(Tabs.instances) + Form { + BrowsingSettings() + } + .tabItem { + Label("Browsing", systemImage: "list.and.film") + } + .tag(Tabs.browsing) + Form { PlaybackSettings() } @@ -49,6 +57,7 @@ struct SettingsView: View { AccountSelectionView() #endif InstancesSettings() + BrowsingSettings() PlaybackSettings() ServicesSettings() } @@ -69,7 +78,7 @@ struct SettingsView: View { #endif } #if os(tvOS) - .background(.thickMaterial) + .background(.black) #endif #endif } diff --git a/Shared/Videos/HorizontalCells.swift b/Shared/Videos/HorizontalCells.swift index 938f25f8..194184e2 100644 --- a/Shared/Videos/HorizontalCells.swift +++ b/Shared/Videos/HorizontalCells.swift @@ -30,7 +30,7 @@ struct HorizontalCells: View { #if os(tvOS) .frame(height: 560) #else - .frame(height: 250) + .frame(height: 290) #endif .edgesIgnoringSafeArea(.horizontal) diff --git a/Shared/Videos/VideoBanner.swift b/Shared/Videos/VideoBanner.swift index 12725321..b4d7ccf2 100644 --- a/Shared/Videos/VideoBanner.swift +++ b/Shared/Videos/VideoBanner.swift @@ -88,7 +88,7 @@ struct VideoBanner: View { private var thumbnailWidth: Double { #if os(tvOS) - 230 + 250 #else 100 #endif diff --git a/Shared/Videos/VideoCell.swift b/Shared/Videos/VideoCell.swift index 9250648a..43127b83 100644 --- a/Shared/Videos/VideoCell.swift +++ b/Shared/Videos/VideoCell.swift @@ -16,6 +16,9 @@ struct VideoCell: View { @EnvironmentObject private var player @EnvironmentObject private var thumbnails + @Default(.channelOnThumbnail) private var channelOnThumbnail + @Default(.timeOnThumbnail) private var timeOnThumbnail + var body: some View { Group { Button(action: { @@ -73,15 +76,20 @@ struct VideoCell: View { videoDetail(video.title, lineLimit: 5) .frame(minWidth: 0, maxWidth: .infinity, alignment: .leading) - videoDetail(video.author) + if !channelOnThumbnail { + Text(video.channel.name) + .fontWeight(.semibold) + .foregroundColor(.secondary) + } if additionalDetailsAvailable { Spacer() - HStack { + HStack(spacing: 15) { if let date = video.publishedDate { VStack { Image(systemName: "calendar") + .frame(height: 15) Text(date) } } @@ -89,9 +97,18 @@ struct VideoCell: View { if video.views > 0 { VStack { Image(systemName: "eye") + .frame(height: 15) Text(video.viewsCount!) } } + + if !timeOnThumbnail, let time = video.length.formattedAsPlaybackTime() { + VStack { + Image(systemName: "clock") + .frame(height: 15) + Text(time) + } + } } .foregroundColor(.secondary) } @@ -133,27 +150,60 @@ struct VideoCell: View { thumbnail VStack(alignment: .leading, spacing: 0) { - videoDetail(video.title, lineLimit: additionalDetailsAvailable ? 2 : 3) + Group { + VStack(alignment: .leading, spacing: 0) { + videoDetail(video.title, lineLimit: channelOnThumbnail ? 3 : 2) + #if os(tvOS) + .frame(minHeight: 60, alignment: .top) + #elseif os(macOS) + .frame(minHeight: 32, alignment: .top) + #else + .frame(minHeight: 40, alignment: .top) + #endif + if !channelOnThumbnail { + Text(video.channel.name) + .fontWeight(.semibold) + .foregroundColor(.secondary) + .padding(.top, 4) + .padding(.bottom, 6) + } + } + } #if os(tvOS) - .frame(minHeight: additionalDetailsAvailable ? 80 : 120, alignment: .top) + .frame(minHeight: channelOnThumbnail ? 80 : 120, alignment: .top) #elseif os(macOS) - .frame(minHeight: 30, alignment: .top) + .frame(minHeight: 60, alignment: .top) #else - .frame(minHeight: 50, alignment: .top) + .frame(minHeight: 80, alignment: .top) #endif .padding(.bottom, 4) HStack(spacing: 8) { if let date = video.publishedDate { - Image(systemName: "calendar") - Text(date) + HStack(spacing: 2) { + Image(systemName: "calendar") + Text(date) + .allowsTightening(true) + } } if video.views > 0 { - Image(systemName: "eye") - Text(video.viewsCount!) + HStack(spacing: 2) { + Image(systemName: "eye") + Text(video.viewsCount!) + } + } + + if let time = video.length.formattedAsPlaybackTime(), !timeOnThumbnail { + Spacer() + + HStack(spacing: 2) { + Image(systemName: "clock") + Text(time) + } } } + .lineLimit(1) .foregroundColor(.secondary) .frame(minHeight: 30, alignment: .top) #if os(tvOS) @@ -169,7 +219,7 @@ struct VideoCell: View { } var additionalDetailsAvailable: Bool { - video.publishedDate != nil || video.views != 0 + video.publishedDate != nil || video.views != 0 || (!timeOnThumbnail && !video.length.formattedAsPlaybackTime().isNil) } var thumbnail: some View { @@ -186,7 +236,9 @@ struct VideoCell: View { Spacer() - DetailBadge(text: video.author, style: .prominent) + if channelOnThumbnail { + DetailBadge(text: video.author, style: .prominent) + } } .padding(10) @@ -195,7 +247,7 @@ struct VideoCell: View { HStack(alignment: .top) { Spacer() - if let time = video.length.formattedAsPlaybackTime() { + if timeOnThumbnail, let time = video.length.formattedAsPlaybackTime() { DetailBadge(text: time, style: .prominent) } } @@ -268,7 +320,11 @@ struct VideoCell_Preview: PreviewProvider { Group { VideoCell(video: Video.fixture) } - .frame(maxWidth: 300, maxHeight: 200) + #if os(macOS) + .frame(maxWidth: 600, maxHeight: 400) + #elseif os(iOS) + .frame(maxWidth: 300, maxHeight: 200) + #endif .injectFixtureEnvironmentObjects() } }