Setting for player sidebar

This commit is contained in:
Arkadiusz Fal 2021-11-04 00:00:17 +01:00
parent f8e6560698
commit c69d60f3ee
7 changed files with 129 additions and 71 deletions

View File

@ -82,6 +82,7 @@
372915E72687E3B900F5A35B /* Defaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 372915E52687E3B900F5A35B /* Defaults.swift */; }; 372915E72687E3B900F5A35B /* Defaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 372915E52687E3B900F5A35B /* Defaults.swift */; };
372915E82687E3B900F5A35B /* Defaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 372915E52687E3B900F5A35B /* Defaults.swift */; }; 372915E82687E3B900F5A35B /* Defaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 372915E52687E3B900F5A35B /* Defaults.swift */; };
3730D8A02712E2B70020ED53 /* NowPlayingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3730D89F2712E2B70020ED53 /* NowPlayingView.swift */; }; 3730D8A02712E2B70020ED53 /* NowPlayingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3730D89F2712E2B70020ED53 /* NowPlayingView.swift */; };
3730F75A2733481E00F385FC /* RelatedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 373197D82732015300EF734F /* RelatedView.swift */; };
373197D92732015300EF734F /* RelatedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 373197D82732015300EF734F /* RelatedView.swift */; }; 373197D92732015300EF734F /* RelatedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 373197D82732015300EF734F /* RelatedView.swift */; };
373197DA2732060100EF734F /* RelatedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 373197D82732015300EF734F /* RelatedView.swift */; }; 373197DA2732060100EF734F /* RelatedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 373197D82732015300EF734F /* RelatedView.swift */; };
37319F0527103F94004ECCD0 /* PlayerQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37319F0427103F94004ECCD0 /* PlayerQueue.swift */; }; 37319F0527103F94004ECCD0 /* PlayerQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37319F0427103F94004ECCD0 /* PlayerQueue.swift */; };
@ -1876,6 +1877,7 @@
3700155C271B0D4D0049C794 /* PipedAPI.swift in Sources */, 3700155C271B0D4D0049C794 /* PipedAPI.swift in Sources */,
37D4B19826717E1500C925CA /* Video.swift in Sources */, 37D4B19826717E1500C925CA /* Video.swift in Sources */,
37599F31272B42810087F250 /* FavoriteItem.swift in Sources */, 37599F31272B42810087F250 /* FavoriteItem.swift in Sources */,
3730F75A2733481E00F385FC /* RelatedView.swift in Sources */,
375168D72700FDB8008F96A6 /* Debounce.swift in Sources */, 375168D72700FDB8008F96A6 /* Debounce.swift in Sources */,
37D526DF2720AC4400ED2F5E /* VideosAPI.swift in Sources */, 37D526DF2720AC4400ED2F5E /* VideosAPI.swift in Sources */,
37D4B0E52671614900C925CA /* PearvidiousApp.swift in Sources */, 37D4B0E52671614900C925CA /* PearvidiousApp.swift in Sources */,

View File

@ -1,6 +1,18 @@
import Defaults import Defaults
import Foundation import Foundation
enum PlayerSidebarSetting: String, CaseIterable, Defaults.Serializable {
case always, whenFits, never
static var defaultValue: Self {
#if os(macOS)
.always
#else
.whenFits
#endif
}
}
extension Defaults.Keys { extension Defaults.Keys {
static let invidiousInstanceID = "default-invidious-instance" static let invidiousInstanceID = "default-invidious-instance"
static let pipedInstanceID = "default-piped-instance" static let pipedInstanceID = "default-piped-instance"
@ -40,6 +52,7 @@ extension Defaults.Keys {
]) ])
static let quality = Key<Stream.ResolutionSetting>("quality", default: .hd720pFirstThenBest) static let quality = Key<Stream.ResolutionSetting>("quality", default: .hd720pFirstThenBest)
static let playerSidebar = Key<PlayerSidebarSetting>("playerSidebar", default: PlayerSidebarSetting.defaultValue)
static let recentlyOpened = Key<[RecentItem]>("recentlyOpened", default: []) static let recentlyOpened = Key<[RecentItem]>("recentlyOpened", default: [])

View File

@ -2,6 +2,7 @@ import Foundation
import SwiftUI import SwiftUI
struct PlayerQueueView: View { struct PlayerQueueView: View {
@Binding var sidebarQueue: Bool
@Binding var fullScreen: Bool @Binding var fullScreen: Bool
@EnvironmentObject<PlayerModel> private var player @EnvironmentObject<PlayerModel> private var player
@ -10,7 +11,9 @@ struct PlayerQueueView: View {
List { List {
Group { Group {
playingNext playingNext
if sidebarQueue {
related related
}
playedPreviously playedPreviously
} }
#if !os(iOS) #if !os(iOS)
@ -119,7 +122,7 @@ struct PlayerQueueView: View {
struct PlayerQueueView_Previews: PreviewProvider { struct PlayerQueueView_Previews: PreviewProvider {
static var previews: some View { static var previews: some View {
VStack { VStack {
PlayerQueueView(fullScreen: .constant(true)) PlayerQueueView(sidebarQueue: .constant(true), fullScreen: .constant(true))
} }
.injectFixtureEnvironmentObjects() .injectFixtureEnvironmentObjects()
} }

View File

@ -58,7 +58,7 @@ struct VideoDetails: View {
} }
.padding(.horizontal) .padding(.horizontal)
if !video.isNil, !sidebarQueue { if !sidebarQueue {
pagePicker pagePicker
.padding(.horizontal) .padding(.horizontal)
} }
@ -87,25 +87,19 @@ struct VideoDetails: View {
detailsPage detailsPage
} }
case .queue: case .queue:
PlayerQueueView(fullScreen: $fullScreen) PlayerQueueView(sidebarQueue: $sidebarQueue, fullScreen: $fullScreen)
.edgesIgnoringSafeArea(.horizontal) .edgesIgnoringSafeArea(.horizontal)
case .related: case .related:
#if os(macOS)
EmptyView()
#else
RelatedView() RelatedView()
.edgesIgnoringSafeArea(.horizontal) .edgesIgnoringSafeArea(.horizontal)
#endif
} }
} }
.padding(.top, inNavigationView && fullScreen ? 10 : 0) .padding(.top, inNavigationView && fullScreen ? 10 : 0)
.onAppear { .onAppear {
#if !os(macOS)
if video.isNil { if video.isNil {
currentPage = .queue currentPage = .queue
} }
#endif
guard video != nil, accounts.app.supportsSubscriptions else { guard video != nil, accounts.app.supportsSubscriptions else {
subscribed = false subscribed = false
@ -115,15 +109,13 @@ struct VideoDetails: View {
subscribed = subscriptions.isSubscribing(video!.channel.id) subscribed = subscriptions.isSubscribing(video!.channel.id)
} }
.onChange(of: sidebarQueue) { queue in .onChange(of: sidebarQueue) { queue in
#if !os(macOS)
if queue { if queue {
if currentPage == .queue { if currentPage == .queue {
currentPage = .details currentPage = .details
} }
} else { } else if video.isNil {
currentPage = .queue currentPage = .queue
} }
#endif
} }
.edgesIgnoringSafeArea(.horizontal) .edgesIgnoringSafeArea(.horizontal)
.frame(minWidth: 0, maxWidth: .infinity, alignment: .leading) .frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
@ -134,9 +126,7 @@ struct VideoDetails: View {
if video != nil { if video != nil {
Text(video!.title) Text(video!.title)
.onAppear { .onAppear {
#if !os(macOS)
currentPage = .details currentPage = .details
#endif
} }
.font(.title2.bold()) .font(.title2.bold())
@ -225,11 +215,13 @@ struct VideoDetails: View {
var pagePicker: some View { var pagePicker: some View {
Picker("Page", selection: $currentPage) { Picker("Page", selection: $currentPage) {
if !video.isNil {
Text("Details").tag(Page.details) Text("Details").tag(Page.details)
Text("Related").tag(Page.related) Text("Related").tag(Page.related)
}
Text("Queue").tag(Page.queue) Text("Queue").tag(Page.queue)
} }
.labelsHidden()
.pickerStyle(.segmented) .pickerStyle(.segmented)
.onDisappear { .onDisappear {
currentPage = .details currentPage = .details

View File

@ -13,21 +13,19 @@ struct VideoPlayerView: View {
#endif #endif
} }
@State private var playerSize: CGSize = .zero
@State private var fullScreen = false @State private var fullScreen = false
#if os(iOS) #if os(iOS)
@Environment(\.dismiss) private var dismiss @Environment(\.dismiss) private var dismiss
@Environment(\.horizontalSizeClass) private var horizontalSizeClass @Environment(\.horizontalSizeClass) private var horizontalSizeClass
@Environment(\.verticalSizeClass) private var verticalSizeClass @Environment(\.verticalSizeClass) private var verticalSizeClass
private var idiom: UIUserInterfaceIdiom {
UIDevice.current.userInterfaceIdiom
}
#endif #endif
@EnvironmentObject<PlayerModel> private var player @EnvironmentObject<PlayerModel> private var player
var body: some View { var body: some View {
GeometryReader { geometry in
#if os(macOS) #if os(macOS)
HSplitView { HSplitView {
content content
@ -37,10 +35,15 @@ struct VideoPlayerView: View {
HStack(spacing: 0) { HStack(spacing: 0) {
content content
} }
#if os(iOS) .onAppear {
self.playerSize = geometry.size
}
.onChange(of: geometry.size) { size in
self.playerSize = size
}
.navigationBarHidden(true) .navigationBarHidden(true)
#endif #endif
#endif }
} }
var content: some View { var content: some View {
@ -92,7 +95,7 @@ struct VideoPlayerView: View {
} }
#else #else
VideoDetails(fullScreen: $fullScreen) VideoDetails(sidebarQueue: sidebarQueueBinding, fullScreen: $fullScreen)
#endif #endif
} }
.background() .background()
@ -105,12 +108,14 @@ struct VideoPlayerView: View {
#endif #endif
#if os(iOS) #if os(iOS)
if sidebarQueue { if sidebarQueue {
PlayerQueueView(fullScreen: $fullScreen) PlayerQueueView(sidebarQueue: .constant(true), fullScreen: $fullScreen)
.frame(maxWidth: 350) .frame(maxWidth: 350)
} }
#elseif os(macOS) #elseif os(macOS)
PlayerQueueView(fullScreen: $fullScreen) if Defaults[.playerSidebar] != .never {
PlayerQueueView(sidebarQueue: sidebarQueueBinding, fullScreen: $fullScreen)
.frame(minWidth: 250) .frame(minWidth: 250)
}
#endif #endif
} }
.onDisappear { .onDisappear {
@ -140,18 +145,23 @@ struct VideoPlayerView: View {
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: geometry.size.width / VideoPlayerView.defaultAspectRatio) .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: geometry.size.width / VideoPlayerView.defaultAspectRatio)
} }
#if os(iOS)
var sidebarQueue: Bool { var sidebarQueue: Bool {
horizontalSizeClass == .regular && idiom == .pad switch Defaults[.playerSidebar] {
case .never:
return false
case .always:
return true
case .whenFits:
return playerSize.width > 900
}
} }
var sidebarQueueBinding: Binding<Bool> { var sidebarQueueBinding: Binding<Bool> {
Binding( Binding(
get: { self.sidebarQueue }, get: { sidebarQueue },
set: { _ in } set: { _ in }
) )
} }
#endif
} }
struct VideoPlayerView_Previews: PreviewProvider { struct VideoPlayerView_Previews: PreviewProvider {

View File

@ -3,6 +3,13 @@ import SwiftUI
struct PlaybackSettings: View { struct PlaybackSettings: View {
@Default(.quality) private var quality @Default(.quality) private var quality
@Default(.playerSidebar) private var playerSidebar
#if os(iOS)
private var idiom: UIUserInterfaceIdiom {
UIDevice.current.userInterfaceIdiom
}
#endif
var body: some View { var body: some View {
Section(header: Text("Quality")) { Section(header: Text("Quality")) {
@ -18,10 +25,41 @@ struct PlaybackSettings: View {
#elseif os(tvOS) #elseif os(tvOS)
.pickerStyle(.inline) .pickerStyle(.inline)
#endif #endif
}
#if os(iOS)
if idiom == .pad {
playerSidebarSection
}
#elseif os(macOS)
playerSidebarSection
#endif
#if os(macOS) #if os(macOS)
Spacer() Spacer()
#endif #endif
} }
private var playerSidebarSection: some View {
Section(header: Text("Player Sidebar")) {
Picker("Player Sidebar", selection: $playerSidebar) {
#if os(macOS)
Text("Show").tag(PlayerSidebarSetting.always)
#endif
#if os(iOS)
Text("Show when space permits").tag(PlayerSidebarSetting.whenFits)
#endif
Text("Hide").tag(PlayerSidebarSetting.never)
}
.labelsHidden()
#if os(iOS)
.pickerStyle(.automatic)
#elseif os(tvOS)
.pickerStyle(.inline)
#endif
}
} }
} }

View File

@ -5,7 +5,7 @@ import SwiftUI
struct SettingsView: View { struct SettingsView: View {
#if os(macOS) #if os(macOS)
private enum Tabs: Hashable { private enum Tabs: Hashable {
case playback, services, instances case instances, playback, services
} }
#endif #endif
@ -24,14 +24,6 @@ struct SettingsView: View {
} }
.tag(Tabs.instances) .tag(Tabs.instances)
Form {
ServicesSettings()
}
.tabItem {
Label("Services", systemImage: "puzzlepiece.extension")
}
.tag(Tabs.services)
Form { Form {
PlaybackSettings() PlaybackSettings()
} }
@ -39,6 +31,14 @@ struct SettingsView: View {
Label("Playback", systemImage: "play.rectangle.on.rectangle.fill") Label("Playback", systemImage: "play.rectangle.on.rectangle.fill")
} }
.tag(Tabs.playback) .tag(Tabs.playback)
Form {
ServicesSettings()
}
.tabItem {
Label("Services", systemImage: "puzzlepiece.extension")
}
.tag(Tabs.services)
} }
.padding(20) .padding(20)
.frame(width: 400, height: 310) .frame(width: 400, height: 310)
@ -49,8 +49,8 @@ struct SettingsView: View {
AccountSelectionView() AccountSelectionView()
#endif #endif
InstancesSettings() InstancesSettings()
ServicesSettings()
PlaybackSettings() PlaybackSettings()
ServicesSettings()
} }
.navigationTitle("Settings") .navigationTitle("Settings")
.toolbar { .toolbar {