Actions buttons settings

This commit is contained in:
Arkadiusz Fal 2022-12-19 11:29:18 +01:00
parent 636e8205fe
commit 5d4983d6d2
4 changed files with 180 additions and 68 deletions

View File

@ -188,6 +188,16 @@ extension Defaults.Keys {
static let playerActionsButtonLabelStyle = Key<ButtonLabelStyle>("playerActionsButtonLabelStyle", default: .iconAndText) static let playerActionsButtonLabelStyle = Key<ButtonLabelStyle>("playerActionsButtonLabelStyle", default: .iconAndText)
static let systemControlsCommands = Key<SystemControlsCommands>("systemControlsCommands", default: .restartAndAdvanceToNext) static let systemControlsCommands = Key<SystemControlsCommands>("systemControlsCommands", default: .restartAndAdvanceToNext)
static let actionButtonShareEnabled = Key<Bool>("actionButtonShareEnabled", default: true)
static let actionButtonAddToPlaylistEnabled = Key<Bool>("actionButtonAddToPlaylistEnabled", default: true)
static let actionButtonSubscribeEnabled = Key<Bool>("actionButtonSubscribeEnabled", default: false)
static let actionButtonSettingsEnabled = Key<Bool>("actionButtonSettingsEnabled", default: true)
static let actionButtonNextEnabled = Key<Bool>("actionButtonNextEnabled", default: true)
static let actionButtonHideEnabled = Key<Bool>("actionButtonHideEnabled", default: false)
static let actionButtonCloseEnabled = Key<Bool>("actionButtonCloseEnabled", default: true)
static let actionButtonNextQueueCountEnabled = Key<Bool>("actionButtonNextQueueCountEnabled", default: true)
static let mpvCacheSecs = Key<String>("mpvCacheSecs", default: "120") static let mpvCacheSecs = Key<String>("mpvCacheSecs", default: "120")
static let mpvCachePauseWait = Key<String>("mpvCachePauseWait", default: "3") static let mpvCachePauseWait = Key<String>("mpvCachePauseWait", default: "3")
static let mpvEnableLogging = Key<Bool>("mpvEnableLogging", default: false) static let mpvEnableLogging = Key<Bool>("mpvEnableLogging", default: false)

View File

@ -2,6 +2,16 @@ import Defaults
import SwiftUI import SwiftUI
struct VideoActions: View { struct VideoActions: View {
enum Action: String, CaseIterable {
case share
case addToPlaylist
case subscribe
case settings
case next
case hide
case close
}
@ObservedObject private var accounts = AccountsModel.shared @ObservedObject private var accounts = AccountsModel.shared
var navigation = NavigationModel.shared var navigation = NavigationModel.shared
@ObservedObject private var subscriptions = SubscribedChannelsModel.shared @ObservedObject private var subscriptions = SubscribedChannelsModel.shared
@ -12,60 +22,112 @@ struct VideoActions: View {
@Default(.openWatchNextOnClose) private var openWatchNextOnClose @Default(.openWatchNextOnClose) private var openWatchNextOnClose
@Default(.playerActionsButtonLabelStyle) private var playerActionsButtonLabelStyle @Default(.playerActionsButtonLabelStyle) private var playerActionsButtonLabelStyle
@Default(.actionButtonShareEnabled) private var actionButtonShareEnabled
@Default(.actionButtonAddToPlaylistEnabled) private var actionButtonAddToPlaylistEnabled
@Default(.actionButtonSubscribeEnabled) private var actionButtonSubscribeEnabled
@Default(.actionButtonSettingsEnabled) private var actionButtonSettingsEnabled
@Default(.actionButtonNextEnabled) private var actionButtonNextEnabled
@Default(.actionButtonHideEnabled) private var actionButtonHideEnabled
@Default(.actionButtonCloseEnabled) private var actionButtonCloseEnabled
@Default(.actionButtonNextQueueCountEnabled) private var actionButtonNextQueueCountEnabled
var body: some View { var body: some View {
HStack(spacing: 6) { HStack(spacing: 6) {
if let video { ForEach(Action.allCases, id: \.self) { action in
#if !os(tvOS) actionBody(action)
if video.isShareable { .frame(maxWidth: .infinity)
}
}
.multilineTextAlignment(.center)
.frame(maxWidth: .infinity)
.frame(height: 50)
.borderBottom(height: 0.5, color: Color("ControlsBorderColor"))
.foregroundColor(.accentColor)
}
func isVisible(_ action: Action) -> Bool {
switch action {
case .share:
return actionButtonShareEnabled
case .addToPlaylist:
return actionButtonAddToPlaylistEnabled
case .subscribe:
return actionButtonSubscribeEnabled
case .settings:
return actionButtonSettingsEnabled
case .next:
return actionButtonNextEnabled
case .hide:
return actionButtonHideEnabled
case .close:
return actionButtonCloseEnabled
}
}
func isActionable(_ action: Action) -> Bool {
switch action {
case .share:
return video?.isShareable ?? false
case .addToPlaylist:
return !(video?.isLocal ?? true)
case .subscribe:
return !(video?.isLocal ?? true) && accounts.signedIn && accounts.app.supportsSubscriptions
case .settings:
return video != nil
default:
return true
}
}
@ViewBuilder func actionBody(_ action: Action) -> some View {
if isVisible(action) {
Group {
switch action {
case .share:
ShareButton(contentItem: .init(video: video)) { ShareButton(contentItem: .init(video: video)) {
actionButton("Share", systemImage: "square.and.arrow.up") actionButton("Share", systemImage: "square.and.arrow.up")
} }
case .addToPlaylist:
Spacer()
}
#endif
if !video.isLocal {
if accounts.signedIn, accounts.app.supportsUserPlaylists {
actionButton("Add", systemImage: "text.badge.plus") { actionButton("Add", systemImage: "text.badge.plus") {
guard let video else { return }
navigation.presentAddToPlaylist(video) navigation.presentAddToPlaylist(video)
} }
Spacer() case .subscribe:
} if let channel = video?.channel,
if accounts.signedIn, accounts.app.supportsSubscriptions { subscriptions.isSubscribing(channel.id)
if subscriptions.isSubscribing(video.channel.id) { {
actionButton("Unsubscribe", systemImage: "xmark.circle") { actionButton("Unsubscribe", systemImage: "xmark.circle") {
#if os(tvOS) #if os(tvOS)
subscriptions.unsubscribe(video.channel.id) subscriptions.unsubscribe(channel.id)
#else #else
navigation.presentUnsubscribeAlert(video.channel, subscriptions: subscriptions) navigation.presentUnsubscribeAlert(channel, subscriptions: subscriptions)
#endif #endif
} }
} else { } else {
actionButton("Subscribe", systemImage: "star.circle") { actionButton("Subscribe", systemImage: "star.circle") {
guard let video else { return }
subscriptions.subscribe(video.channel.id) { subscriptions.subscribe(video.channel.id) {
navigation.sidebarSectionChanged.toggle() navigation.sidebarSectionChanged.toggle()
} }
} }
} }
Spacer() case .settings:
actionButton("Settings", systemImage: "gear") {
withAnimation(ControlOverlaysModel.animation) {
ControlOverlaysModel.shared.show()
} }
} }
} else { case .next:
Spacer() actionButton(nextLabel, systemImage: Constants.nextSystemImage) {
}
actionButton("Next", systemImage: Constants.nextSystemImage) {
WatchNextViewModel.shared.userInteractedOpen(player.currentItem) WatchNextViewModel.shared.userInteractedOpen(player.currentItem)
} }
case .hide:
Spacer()
actionButton("Hide", systemImage: "chevron.down") { actionButton("Hide", systemImage: "chevron.down") {
player.hide(animate: true) player.hide(animate: true)
} }
Spacer() case .close:
actionButton("Close", systemImage: "xmark") { actionButton("Close", systemImage: "xmark") {
if openWatchNextOnClose { if openWatchNextOnClose {
player.pause() player.pause()
@ -75,12 +137,17 @@ struct VideoActions: View {
} }
} }
} }
.padding(.horizontal) }
.multilineTextAlignment(.center) .disabled(!isActionable(action))
.frame(maxWidth: .infinity) }
.frame(height: 50) }
.borderBottom(height: 0.5, color: Color("ControlsBorderColor"))
.foregroundColor(.accentColor) var nextLabel: String {
if actionButtonNextQueueCountEnabled, !player.queue.isEmpty {
return "\("Next".localized())\(player.queue.count)"
}
return "Next".localized()
} }
func actionButton( func actionButton(

View File

@ -33,6 +33,14 @@ struct PlayerSettings: View {
@Default(.openWatchNextOnFinishedWatching) private var openWatchNextOnFinishedWatching @Default(.openWatchNextOnFinishedWatching) private var openWatchNextOnFinishedWatching
@Default(.openWatchNextOnFinishedWatchingDelay) private var openWatchNextOnFinishedWatchingDelay @Default(.openWatchNextOnFinishedWatchingDelay) private var openWatchNextOnFinishedWatchingDelay
@Default(.actionButtonShareEnabled) private var actionButtonShareEnabled
@Default(.actionButtonSubscribeEnabled) private var actionButtonSubscribeEnabled
@Default(.actionButtonNextEnabled) private var actionButtonNextEnabled
@Default(.actionButtonCloseEnabled) private var actionButtonCloseEnabled
@Default(.actionButtonAddToPlaylistEnabled) private var actionButtonAddToPlaylistEnabled
@Default(.actionButtonSettingsEnabled) private var actionButtonSettingsEnabled
@Default(.actionButtonHideEnabled) private var actionButtonHideEnabled
@Default(.actionButtonNextQueueCountEnabled) private var actionButtonNextQueueCountEnabled
@ObservedObject private var accounts = AccountsModel.shared @ObservedObject private var accounts = AccountsModel.shared
private var player = PlayerModel.shared private var player = PlayerModel.shared
@ -75,6 +83,13 @@ struct PlayerSettings: View {
systemControlsCommandsPicker systemControlsCommandsPicker
} }
#if !os(tvOS)
Section(header: SettingsHeader(text: "Actions Buttons")) {
actionButtonToggles
}
actionButtonNextQueueCountEnabledToggle
#endif
Section(header: SettingsHeader(text: "Watch Next")) { Section(header: SettingsHeader(text: "Watch Next")) {
openWatchNextOnFinishedWatchingToggle openWatchNextOnFinishedWatchingToggle
openWatchNextOnFinishedWatchingDelayTextField openWatchNextOnFinishedWatchingDelayTextField
@ -210,6 +225,24 @@ struct PlayerSettings: View {
.multilineTextAlignment(.trailing) .multilineTextAlignment(.trailing)
} }
@ViewBuilder private var actionButtonToggles: some View {
actionButtonToggle("Share", $actionButtonShareEnabled)
actionButtonToggle("Add to Playlist", $actionButtonAddToPlaylistEnabled)
actionButtonToggle("Subscribe/Unsubscribe", $actionButtonSubscribeEnabled)
actionButtonToggle("Settings", $actionButtonSettingsEnabled)
actionButtonToggle("Watch Next", $actionButtonNextEnabled)
actionButtonToggle("Hide player", $actionButtonHideEnabled)
actionButtonToggle("Close video", $actionButtonCloseEnabled)
}
private func actionButtonToggle(_ name: String, _ value: Binding<Bool>) -> some View {
Toggle(name, isOn: value)
}
var actionButtonNextQueueCountEnabledToggle: some View {
Toggle("Show queue items count in Watch Next button label", isOn: $actionButtonNextQueueCountEnabled)
}
private var sidebarPicker: some View { private var sidebarPicker: some View {
Picker("Sidebar", selection: $playerSidebar) { Picker("Sidebar", selection: $playerSidebar) {
#if os(macOS) #if os(macOS)

View File

@ -21,8 +21,10 @@ struct ShareButton<LabelView: View>: View {
@ViewBuilder var body: some View { @ViewBuilder var body: some View {
// TODO: this should work with other content item types // TODO: this should work with other content item types
if let video = contentItem.video, !video.localStreamIsFile {
Menu { Menu {
if let video = contentItem.video,
!video.localStreamIsFile
{
if video.localStreamIsRemoteURL { if video.localStreamIsRemoteURL {
remoteURLAction remoteURLAction
} else { } else {
@ -32,6 +34,7 @@ struct ShareButton<LabelView: View>: View {
youtubeActions youtubeActions
} }
} }
}
} label: { } label: {
label label
} }
@ -40,7 +43,6 @@ struct ShareButton<LabelView: View>: View {
.frame(maxWidth: 60) .frame(maxWidth: 60)
#endif #endif
} }
}
private var instanceActions: some View { private var instanceActions: some View {
Group { Group {