mirror of
https://github.com/yattee/yattee.git
synced 2024-12-22 21:43:41 +00:00
New actions buttons
This commit is contained in:
parent
a7763c5802
commit
8f9fb7ba82
@ -664,6 +664,46 @@ final class PlayerModel: ObservableObject {
|
|||||||
backend.closePiP()
|
backend.closePiP()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var pipImage: String {
|
||||||
|
transitioningToPiP ? "pip.fill" : pipController?.isPictureInPictureActive ?? false ? "pip.exit" : "pip.enter"
|
||||||
|
}
|
||||||
|
|
||||||
|
var fullscreenImage: String {
|
||||||
|
playingFullScreen ? "arrow.down.right.and.arrow.up.left" : "arrow.up.left.and.arrow.down.right"
|
||||||
|
}
|
||||||
|
|
||||||
|
func toggleFullScreenAction() {
|
||||||
|
toggleFullscreen(playingFullScreen, showControls: false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func togglePiPAction() {
|
||||||
|
(pipController?.isPictureInPictureActive ?? false) ? closePiP() : startPiP()
|
||||||
|
}
|
||||||
|
|
||||||
|
#if os(iOS)
|
||||||
|
var lockOrientationImage: String {
|
||||||
|
lockedOrientation.isNil ? "lock.rotation.open" : "lock.rotation"
|
||||||
|
}
|
||||||
|
|
||||||
|
func lockOrientationAction() {
|
||||||
|
if lockedOrientation.isNil {
|
||||||
|
let orientationMask = OrientationTracker.shared.currentInterfaceOrientationMask
|
||||||
|
lockedOrientation = orientationMask
|
||||||
|
let orientation = OrientationTracker.shared.currentInterfaceOrientation
|
||||||
|
Orientation.lockOrientation(orientationMask, andRotateTo: .landscapeLeft)
|
||||||
|
// iOS 16 workaround
|
||||||
|
Orientation.lockOrientation(orientationMask, andRotateTo: orientation)
|
||||||
|
} else {
|
||||||
|
lockedOrientation = nil
|
||||||
|
Orientation.lockOrientation(.allButUpsideDown, andRotateTo: OrientationTracker.shared.currentInterfaceOrientation)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
func replayAction() {
|
||||||
|
backend.seek(to: 0.0, seekType: .userInteracted)
|
||||||
|
}
|
||||||
|
|
||||||
func handleQueueChange() {
|
func handleQueueChange() {
|
||||||
Defaults[.queue] = queue
|
Defaults[.queue] = queue
|
||||||
|
|
||||||
|
@ -201,6 +201,12 @@ extension Defaults.Keys {
|
|||||||
static let actionButtonSettingsEnabled = Key<Bool>("actionButtonSettingsEnabled", default: true)
|
static let actionButtonSettingsEnabled = Key<Bool>("actionButtonSettingsEnabled", default: true)
|
||||||
static let actionButtonHideEnabled = Key<Bool>("actionButtonHideEnabled", default: false)
|
static let actionButtonHideEnabled = Key<Bool>("actionButtonHideEnabled", default: false)
|
||||||
static let actionButtonCloseEnabled = Key<Bool>("actionButtonCloseEnabled", default: true)
|
static let actionButtonCloseEnabled = Key<Bool>("actionButtonCloseEnabled", default: true)
|
||||||
|
static let actionButtonFullScreenEnabled = Key<Bool>("actionButtonFullScreenEnabled", default: false)
|
||||||
|
static let actionButtonPipEnabled = Key<Bool>("actionButtonPipEnabled", default: false)
|
||||||
|
static let actionButtonLockOrientationEnabled = Key<Bool>("actionButtonLockOrientationEnabled", default: false)
|
||||||
|
static let actionButtonRestartEnabled = Key<Bool>("actionButtonRestartEnabled", default: false)
|
||||||
|
static let actionButtonAdvanceToNextItemEnabled = Key<Bool>("actionButtonAdvanceToNextItemEnabled", default: false)
|
||||||
|
static let actionButtonMusicModeEnabled = Key<Bool>("actionButtonMusicModeEnabled", default: true)
|
||||||
|
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
static let playerControlsLockOrientationEnabled = Key<Bool>("playerControlsLockOrientationEnabled", default: true)
|
static let playerControlsLockOrientationEnabled = Key<Bool>("playerControlsLockOrientationEnabled", default: true)
|
||||||
@ -215,7 +221,7 @@ extension Defaults.Keys {
|
|||||||
static let playerControlsRestartEnabled = Key<Bool>("playerControlsRestartEnabled", default: false)
|
static let playerControlsRestartEnabled = Key<Bool>("playerControlsRestartEnabled", default: false)
|
||||||
static let playerControlsAdvanceToNextEnabled = Key<Bool>("playerControlsAdvanceToNextEnabled", default: false)
|
static let playerControlsAdvanceToNextEnabled = Key<Bool>("playerControlsAdvanceToNextEnabled", default: false)
|
||||||
static let playerControlsPlaybackModeEnabled = Key<Bool>("playerControlsPlaybackModeEnabled", default: false)
|
static let playerControlsPlaybackModeEnabled = Key<Bool>("playerControlsPlaybackModeEnabled", default: false)
|
||||||
static let playerControlsMusicModeEnabled = Key<Bool>("playerControlsMusicModeEnabled", default: true)
|
static let playerControlsMusicModeEnabled = Key<Bool>("playerControlsMusicModeEnabled", default: false)
|
||||||
|
|
||||||
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")
|
||||||
|
@ -329,7 +329,7 @@ struct PlayerControls: View {
|
|||||||
var fullscreenButton: some View {
|
var fullscreenButton: some View {
|
||||||
button(
|
button(
|
||||||
"Fullscreen",
|
"Fullscreen",
|
||||||
systemImage: player.playingFullScreen ? "arrow.down.right.and.arrow.up.left" : "arrow.up.left.and.arrow.down.right"
|
systemImage: player.fullscreenImage
|
||||||
) {
|
) {
|
||||||
player.toggleFullscreen(player.playingFullScreen, showControls: false)
|
player.toggleFullscreen(player.playingFullScreen, showControls: false)
|
||||||
}
|
}
|
||||||
@ -367,28 +367,13 @@ struct PlayerControls: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private var pipButton: some View {
|
private var pipButton: some View {
|
||||||
let image = player.transitioningToPiP ? "pip.fill" : player.pipController?.isPictureInPictureActive ?? false ? "pip.exit" : "pip.enter"
|
button("PiP", systemImage: player.pipImage, action: player.togglePiPAction)
|
||||||
return button("PiP", systemImage: image) {
|
|
||||||
(player.pipController?.isPictureInPictureActive ?? false) ? player.closePiP() : player.startPiP()
|
|
||||||
}
|
|
||||||
.disabled(!player.pipPossible)
|
.disabled(!player.pipPossible)
|
||||||
}
|
}
|
||||||
|
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
private var lockOrientationButton: some View {
|
private var lockOrientationButton: some View {
|
||||||
button("Lock Rotation", systemImage: player.lockedOrientation.isNil ? "lock.rotation.open" : "lock.rotation", active: !player.lockedOrientation.isNil) {
|
button("Lock Rotation", systemImage: player.lockOrientationImage, active: !player.lockedOrientation.isNil, action: player.lockOrientationAction)
|
||||||
if player.lockedOrientation.isNil {
|
|
||||||
let orientationMask = OrientationTracker.shared.currentInterfaceOrientationMask
|
|
||||||
player.lockedOrientation = orientationMask
|
|
||||||
let orientation = OrientationTracker.shared.currentInterfaceOrientation
|
|
||||||
Orientation.lockOrientation(orientationMask, andRotateTo: .landscapeLeft)
|
|
||||||
// iOS 16 workaround
|
|
||||||
Orientation.lockOrientation(orientationMask, andRotateTo: orientation)
|
|
||||||
} else {
|
|
||||||
player.lockedOrientation = nil
|
|
||||||
Orientation.lockOrientation(.allButUpsideDown, andRotateTo: OrientationTracker.shared.currentInterfaceOrientation)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -456,9 +441,7 @@ struct PlayerControls: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private var restartVideoButton: some View {
|
private var restartVideoButton: some View {
|
||||||
button("Restart video", systemImage: "backward.end.fill", cornerRadius: 5) {
|
button("Restart video", systemImage: "backward.end.fill", cornerRadius: 5, action: player.replayAction)
|
||||||
player.backend.seek(to: 0.0, seekType: .userInteracted)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private var togglePlayButton: some View {
|
private var togglePlayButton: some View {
|
||||||
|
@ -6,6 +6,14 @@ struct VideoActions: View {
|
|||||||
case share
|
case share
|
||||||
case addToPlaylist
|
case addToPlaylist
|
||||||
case subscribe
|
case subscribe
|
||||||
|
case fullScreen
|
||||||
|
case pip
|
||||||
|
#if os(iOS)
|
||||||
|
case lockOrientation
|
||||||
|
#endif
|
||||||
|
case restart
|
||||||
|
case advanceToNextItem
|
||||||
|
case musicMode
|
||||||
case settings
|
case settings
|
||||||
case hide
|
case hide
|
||||||
case close
|
case close
|
||||||
@ -24,6 +32,12 @@ struct VideoActions: View {
|
|||||||
@Default(.actionButtonAddToPlaylistEnabled) private var actionButtonAddToPlaylistEnabled
|
@Default(.actionButtonAddToPlaylistEnabled) private var actionButtonAddToPlaylistEnabled
|
||||||
@Default(.actionButtonSubscribeEnabled) private var actionButtonSubscribeEnabled
|
@Default(.actionButtonSubscribeEnabled) private var actionButtonSubscribeEnabled
|
||||||
@Default(.actionButtonSettingsEnabled) private var actionButtonSettingsEnabled
|
@Default(.actionButtonSettingsEnabled) private var actionButtonSettingsEnabled
|
||||||
|
@Default(.actionButtonFullScreenEnabled) private var actionButtonFullScreenEnabled
|
||||||
|
@Default(.actionButtonPipEnabled) private var actionButtonPipEnabled
|
||||||
|
@Default(.actionButtonLockOrientationEnabled) private var actionButtonLockOrientationEnabled
|
||||||
|
@Default(.actionButtonRestartEnabled) private var actionButtonRestartEnabled
|
||||||
|
@Default(.actionButtonAdvanceToNextItemEnabled) private var actionButtonAdvanceToNextItemEnabled
|
||||||
|
@Default(.actionButtonMusicModeEnabled) private var actionButtonMusicModeEnabled
|
||||||
@Default(.actionButtonHideEnabled) private var actionButtonHideEnabled
|
@Default(.actionButtonHideEnabled) private var actionButtonHideEnabled
|
||||||
@Default(.actionButtonCloseEnabled) private var actionButtonCloseEnabled
|
@Default(.actionButtonCloseEnabled) private var actionButtonCloseEnabled
|
||||||
|
|
||||||
@ -51,6 +65,20 @@ struct VideoActions: View {
|
|||||||
return actionButtonSubscribeEnabled
|
return actionButtonSubscribeEnabled
|
||||||
case .settings:
|
case .settings:
|
||||||
return actionButtonSettingsEnabled
|
return actionButtonSettingsEnabled
|
||||||
|
case .fullScreen:
|
||||||
|
return actionButtonFullScreenEnabled
|
||||||
|
case .pip:
|
||||||
|
return actionButtonPipEnabled
|
||||||
|
#if os(iOS)
|
||||||
|
case .lockOrientation:
|
||||||
|
return actionButtonLockOrientationEnabled
|
||||||
|
#endif
|
||||||
|
case .restart:
|
||||||
|
return actionButtonRestartEnabled
|
||||||
|
case .advanceToNextItem:
|
||||||
|
return actionButtonAdvanceToNextItemEnabled
|
||||||
|
case .musicMode:
|
||||||
|
return actionButtonMusicModeEnabled
|
||||||
case .hide:
|
case .hide:
|
||||||
return actionButtonHideEnabled
|
return actionButtonHideEnabled
|
||||||
case .close:
|
case .close:
|
||||||
@ -68,6 +96,8 @@ struct VideoActions: View {
|
|||||||
return !(video?.isLocal ?? true) && accounts.signedIn && accounts.app.supportsSubscriptions
|
return !(video?.isLocal ?? true) && accounts.signedIn && accounts.app.supportsSubscriptions
|
||||||
case .settings:
|
case .settings:
|
||||||
return video != nil
|
return video != nil
|
||||||
|
case .advanceToNextItem:
|
||||||
|
return player.isAdvanceToNextItemAvailable
|
||||||
default:
|
default:
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -110,6 +140,23 @@ struct VideoActions: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case .fullScreen:
|
||||||
|
actionButton("Fullscreen", systemImage: player.fullscreenImage, action: player.toggleFullScreenAction)
|
||||||
|
case .pip:
|
||||||
|
actionButton("PiP", systemImage: player.pipImage, action: player.togglePiPAction)
|
||||||
|
#if os(iOS)
|
||||||
|
case .lockOrientation:
|
||||||
|
actionButton("Lock", systemImage: player.lockOrientationImage, active: player.lockedOrientation != nil, action: player.lockOrientationAction)
|
||||||
|
#endif
|
||||||
|
case .restart:
|
||||||
|
actionButton("Replay", systemImage: "backward.end.fill", action: player.replayAction)
|
||||||
|
case .advanceToNextItem:
|
||||||
|
actionButton("Next", systemImage: "forward.fill") {
|
||||||
|
player.advanceToNextItem()
|
||||||
|
}
|
||||||
|
case .musicMode:
|
||||||
|
actionButton("Music", systemImage: "music.note", active: player.musicMode, action: player.toggleMusicMode)
|
||||||
|
|
||||||
case .settings:
|
case .settings:
|
||||||
actionButton("Settings", systemImage: "gear") {
|
actionButton("Settings", systemImage: "gear") {
|
||||||
withAnimation(ControlOverlaysModel.animation) {
|
withAnimation(ControlOverlaysModel.animation) {
|
||||||
@ -138,15 +185,17 @@ struct VideoActions: View {
|
|||||||
func actionButton(
|
func actionButton(
|
||||||
_ name: String,
|
_ name: String,
|
||||||
systemImage: String,
|
systemImage: String,
|
||||||
|
active: Bool = false,
|
||||||
action: @escaping () -> Void = {}
|
action: @escaping () -> Void = {}
|
||||||
) -> some View {
|
) -> some View {
|
||||||
Button(action: action) {
|
Button(action: action) {
|
||||||
VStack(spacing: 3) {
|
VStack(spacing: 3) {
|
||||||
Image(systemName: systemImage)
|
Image(systemName: systemImage)
|
||||||
.frame(width: 20, height: 20)
|
.frame(width: 20, height: 20)
|
||||||
|
.foregroundColor(active ? Color("AppRedColor") : .accentColor)
|
||||||
if playerActionsButtonLabelStyle.text {
|
if playerActionsButtonLabelStyle.text {
|
||||||
Text(name.localized())
|
Text(name.localized())
|
||||||
.foregroundColor(.secondary)
|
.foregroundColor(active ? Color("AppRedColor") : .secondary)
|
||||||
.font(.caption2)
|
.font(.caption2)
|
||||||
.allowsTightening(true)
|
.allowsTightening(true)
|
||||||
}
|
}
|
||||||
|
@ -257,7 +257,7 @@ struct VideoDetails: View {
|
|||||||
|
|
||||||
switch page {
|
switch page {
|
||||||
case .queue:
|
case .queue:
|
||||||
return !player.queue.isEmpty
|
return !sidebarQueue && player.isAdvanceToNextItemAvailable
|
||||||
default:
|
default:
|
||||||
return !video.isLocal
|
return !video.isLocal
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,12 @@ struct PlayerControlsSettings: View {
|
|||||||
@Default(.actionButtonCloseEnabled) private var actionButtonCloseEnabled
|
@Default(.actionButtonCloseEnabled) private var actionButtonCloseEnabled
|
||||||
@Default(.actionButtonAddToPlaylistEnabled) private var actionButtonAddToPlaylistEnabled
|
@Default(.actionButtonAddToPlaylistEnabled) private var actionButtonAddToPlaylistEnabled
|
||||||
@Default(.actionButtonSettingsEnabled) private var actionButtonSettingsEnabled
|
@Default(.actionButtonSettingsEnabled) private var actionButtonSettingsEnabled
|
||||||
|
@Default(.actionButtonFullScreenEnabled) private var actionButtonFullScreenEnabled
|
||||||
|
@Default(.actionButtonPipEnabled) private var actionButtonPipEnabled
|
||||||
|
@Default(.actionButtonLockOrientationEnabled) private var actionButtonLockOrientationEnabled
|
||||||
|
@Default(.actionButtonRestartEnabled) private var actionButtonRestartEnabled
|
||||||
|
@Default(.actionButtonAdvanceToNextItemEnabled) private var actionButtonAdvanceToNextItemEnabled
|
||||||
|
@Default(.actionButtonMusicModeEnabled) private var actionButtonMusicModeEnabled
|
||||||
@Default(.actionButtonHideEnabled) private var actionButtonHideEnabled
|
@Default(.actionButtonHideEnabled) private var actionButtonHideEnabled
|
||||||
|
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
@ -211,6 +217,7 @@ struct PlayerControlsSettings: View {
|
|||||||
.labelStyle(.iconOnly)
|
.labelStyle(.iconOnly)
|
||||||
.padding(7)
|
.padding(7)
|
||||||
.foregroundColor(.accentColor)
|
.foregroundColor(.accentColor)
|
||||||
|
.accessibilityAddTraits(.isButton)
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
.background(RoundedRectangle(cornerRadius: 4).strokeBorder(lineWidth: 1).foregroundColor(.accentColor))
|
.background(RoundedRectangle(cornerRadius: 4).strokeBorder(lineWidth: 1).foregroundColor(.accentColor))
|
||||||
#endif
|
#endif
|
||||||
@ -246,6 +253,7 @@ struct PlayerControlsSettings: View {
|
|||||||
.labelStyle(.iconOnly)
|
.labelStyle(.iconOnly)
|
||||||
.padding(7)
|
.padding(7)
|
||||||
.foregroundColor(.accentColor)
|
.foregroundColor(.accentColor)
|
||||||
|
.accessibilityAddTraits(.isButton)
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
.frame(minHeight: 35)
|
.frame(minHeight: 35)
|
||||||
.background(RoundedRectangle(cornerRadius: 4).strokeBorder(lineWidth: 1).foregroundColor(.accentColor))
|
.background(RoundedRectangle(cornerRadius: 4).strokeBorder(lineWidth: 1).foregroundColor(.accentColor))
|
||||||
@ -265,13 +273,25 @@ struct PlayerControlsSettings: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder private var actionButtonToggles: some View {
|
@ViewBuilder private var actionButtonToggles: some View {
|
||||||
|
Group {
|
||||||
Toggle("Share", isOn: $actionButtonShareEnabled)
|
Toggle("Share", isOn: $actionButtonShareEnabled)
|
||||||
Toggle("Add to Playlist", isOn: $actionButtonAddToPlaylistEnabled)
|
Toggle("Add to Playlist", isOn: $actionButtonAddToPlaylistEnabled)
|
||||||
Toggle("Subscribe/Unsubscribe", isOn: $actionButtonSubscribeEnabled)
|
Toggle("Subscribe/Unsubscribe", isOn: $actionButtonSubscribeEnabled)
|
||||||
Toggle("Settings", isOn: $actionButtonSettingsEnabled)
|
Toggle("Settings", isOn: $actionButtonSettingsEnabled)
|
||||||
|
Toggle("Fullscreen", isOn: $actionButtonFullScreenEnabled)
|
||||||
|
Toggle("Picture in Picture", isOn: $actionButtonPipEnabled)
|
||||||
|
}
|
||||||
|
Group {
|
||||||
|
#if os(iOS)
|
||||||
|
Toggle("Lock orientation", isOn: $actionButtonLockOrientationEnabled)
|
||||||
|
#endif
|
||||||
|
Toggle("Restart", isOn: $actionButtonRestartEnabled)
|
||||||
|
Toggle("Play next item", isOn: $actionButtonAdvanceToNextItemEnabled)
|
||||||
|
Toggle("Music Mode", isOn: $actionButtonMusicModeEnabled)
|
||||||
Toggle("Hide player", isOn: $actionButtonHideEnabled)
|
Toggle("Hide player", isOn: $actionButtonHideEnabled)
|
||||||
Toggle("Close video", isOn: $actionButtonCloseEnabled)
|
Toggle("Close video", isOn: $actionButtonCloseEnabled)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ViewBuilder private var controlButtonToggles: some View {
|
@ViewBuilder private var controlButtonToggles: some View {
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
@ -283,9 +303,9 @@ struct PlayerControlsSettings: View {
|
|||||||
#endif
|
#endif
|
||||||
Toggle("Restart", isOn: $playerControlsRestartEnabled)
|
Toggle("Restart", isOn: $playerControlsRestartEnabled)
|
||||||
Toggle("Play next item", isOn: $playerControlsAdvanceToNextEnabled)
|
Toggle("Play next item", isOn: $playerControlsAdvanceToNextEnabled)
|
||||||
Toggle("Playback mode", isOn: $playerControlsPlaybackModeEnabled)
|
Toggle("Playback Mode", isOn: $playerControlsPlaybackModeEnabled)
|
||||||
#if !os(tvOS)
|
#if !os(tvOS)
|
||||||
Toggle("Music mode", isOn: $playerControlsMusicModeEnabled)
|
Toggle("Music Mode", isOn: $playerControlsMusicModeEnabled)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -247,7 +247,7 @@ struct SettingsView: View {
|
|||||||
case .player:
|
case .player:
|
||||||
return 450
|
return 450
|
||||||
case .controls:
|
case .controls:
|
||||||
return 850
|
return 900
|
||||||
case .quality:
|
case .quality:
|
||||||
return 420
|
return 420
|
||||||
case .history:
|
case .history:
|
||||||
|
Loading…
Reference in New Issue
Block a user