mirror of
https://github.com/yattee/yattee.git
synced 2026-10-23 13:12:53 +00:00
Add keyboard shortcuts to toggle corner layout panels
Playback menu items toggle the info panel below the video (⌥⌘I), the side column (⌥⌘S) and both at once (⌥⌘P) while the corner layout is active. Showing one region from the hidden state brings back only that region; hiding the last visible one hides the whole panel.
This commit is contained in:
@@ -79,6 +79,13 @@ struct PlaybackCommands: Commands {
|
||||
|
||||
// Display modes
|
||||
pipButton
|
||||
|
||||
Divider()
|
||||
|
||||
// Corner layout panels
|
||||
toggleInfoPanelButton
|
||||
toggleSidebarButton
|
||||
toggleAllPanelsButton
|
||||
|
||||
Divider()
|
||||
closeVideoButton
|
||||
@@ -309,6 +316,42 @@ struct PlaybackCommands: Commands {
|
||||
.disabled(!hasActiveVideo || !state.isPiPPossible || state.currentStream?.isAudioOnly == true)
|
||||
}
|
||||
|
||||
// MARK: - Corner Layout Panels
|
||||
|
||||
private var isCornerLayoutActive: Bool {
|
||||
isPlayerExpanded && navigationCoordinator.isCornerLayoutActive
|
||||
}
|
||||
|
||||
private var toggleInfoPanelButton: some View {
|
||||
Button {
|
||||
navigationCoordinator.cornerPanelToggleRequest = CornerPanelToggleRequest(target: .belowVideo)
|
||||
} label: {
|
||||
Text(String(localized: "menu.playback.toggleInfoPanel"))
|
||||
}
|
||||
.keyboardShortcut("i", modifiers: [.command, .option])
|
||||
.disabled(!isCornerLayoutActive)
|
||||
}
|
||||
|
||||
private var toggleSidebarButton: some View {
|
||||
Button {
|
||||
navigationCoordinator.cornerPanelToggleRequest = CornerPanelToggleRequest(target: .sideColumn)
|
||||
} label: {
|
||||
Text(String(localized: "menu.playback.toggleSidebar"))
|
||||
}
|
||||
.keyboardShortcut("s", modifiers: [.command, .option])
|
||||
.disabled(!isCornerLayoutActive)
|
||||
}
|
||||
|
||||
private var toggleAllPanelsButton: some View {
|
||||
Button {
|
||||
navigationCoordinator.cornerPanelToggleRequest = CornerPanelToggleRequest(target: .all)
|
||||
} label: {
|
||||
Text(String(localized: "menu.playback.toggleAllPanels"))
|
||||
}
|
||||
.keyboardShortcut("p", modifiers: [.command, .option])
|
||||
.disabled(!isCornerLayoutActive)
|
||||
}
|
||||
|
||||
// MARK: - Close video button
|
||||
|
||||
private var closeVideoButton: some View {
|
||||
|
||||
@@ -6907,6 +6907,36 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"menu.playback.toggleAllPanels" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Toggle All Panels"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"menu.playback.toggleInfoPanel" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Toggle Info Panel"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"menu.playback.toggleSidebar" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Toggle Sidebar"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"menu.playback.volumeDown" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
|
||||
@@ -165,6 +165,11 @@ final class NavigationCoordinator {
|
||||
/// not collapsed) — the seek pan must not begin from inside it.
|
||||
var cornerSideColumnEdgeRevealInset: CGFloat = 0
|
||||
|
||||
/// Corner layout panel toggle requested from outside the layout (menu
|
||||
/// bar keyboard shortcuts). Each request carries its own id so repeating
|
||||
/// the same shortcut fires again.
|
||||
var cornerPanelToggleRequest: CornerPanelToggleRequest?
|
||||
|
||||
/// Progress bar frame in screen coordinates (for gesture conflict resolution).
|
||||
var progressBarFrame: CGRect = .zero
|
||||
|
||||
@@ -389,3 +394,18 @@ final class NavigationCoordinator {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Corner layout regions a panel toggle request targets.
|
||||
enum CornerPanelToggle: Equatable {
|
||||
/// The info panel below the video (with the comments pill on iOS).
|
||||
case belowVideo
|
||||
/// The tabbed side column on the trailing edge.
|
||||
case sideColumn
|
||||
/// Every region at once — same as the in-player panel toggle button.
|
||||
case all
|
||||
}
|
||||
|
||||
struct CornerPanelToggleRequest: Equatable {
|
||||
let target: CornerPanelToggle
|
||||
let id = UUID()
|
||||
}
|
||||
|
||||
@@ -652,6 +652,10 @@ struct CornerPlayerLayout<PlayerContent: View>: View {
|
||||
panelToggleGeneration += 1
|
||||
}
|
||||
}
|
||||
.onChange(of: appEnvironment?.navigationCoordinator.cornerPanelToggleRequest) { _, request in
|
||||
guard let request else { return }
|
||||
handlePanelToggleRequest(request.target)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Panels
|
||||
@@ -851,6 +855,50 @@ struct CornerPlayerLayout<PlayerContent: View>: View {
|
||||
}
|
||||
}
|
||||
|
||||
/// Keyboard shortcut toggles from the menu bar. `.all` is the toggle
|
||||
/// button; the single-region toggles flip one region and keep the other
|
||||
/// as it is on screen.
|
||||
private func handlePanelToggleRequest(_ target: CornerPanelToggle) {
|
||||
let showsBelow = isPanelVisible && isBelowPanelVisible && hasBelowVideoInfo
|
||||
let showsSide = isPanelVisible && isSideColumnVisible && hasSideColumn
|
||||
switch target {
|
||||
case .all:
|
||||
togglePanel()
|
||||
case .belowVideo:
|
||||
guard hasBelowVideoInfo else { return }
|
||||
setRegionsVisible(below: !showsBelow, side: showsSide)
|
||||
case .sideColumn:
|
||||
guard hasSideColumn else { return }
|
||||
setRegionsVisible(below: showsBelow, side: !showsSide)
|
||||
}
|
||||
}
|
||||
|
||||
/// Shows exactly the given regions, animated like the toggle button.
|
||||
/// Hiding the last visible region hides the whole panel instead (video
|
||||
/// fullscreen state), leaving both regions armed for the next show.
|
||||
private func setRegionsVisible(below: Bool, side: Bool) {
|
||||
let showsAny = (below && hasBelowVideoInfo) || (side && hasSideColumn)
|
||||
withAnimation(.easeInOut(duration: 0.25)) {
|
||||
// Drop any in-flight drag geometry — the flags alone define
|
||||
// the layout from here
|
||||
isRevealDragActive = false
|
||||
isSideColumnRevealDragActive = false
|
||||
sideColumnDragOffset = 0
|
||||
belowPanelDragOffset = 0
|
||||
if !below || !showsAny { collapseBelowPanelUnderVideo() }
|
||||
isBelowPanelVisible = showsAny ? below : true
|
||||
isSideColumnVisible = showsAny ? side : true
|
||||
isPanelVisible = showsAny
|
||||
panelToggleGeneration += 1
|
||||
// Also gates the macOS window aspect lock
|
||||
// (`isCornerPanelLayoutActive`)
|
||||
if settingsManager?.landscapeDetailsPanelVisible != showsAny {
|
||||
settingsManager?.landscapeDetailsPanelVisible = showsAny
|
||||
settingsManager?.landscapeDetailsPanelLastVisible = showsAny
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Hiding everything grows the video over the below panel, so an
|
||||
/// expanded panel (raised above the video) must drop back to its home
|
||||
/// geometry under the video first.
|
||||
|
||||
Reference in New Issue
Block a user