Skip to content

Commit

Permalink
refactor: autohide controls
Browse files Browse the repository at this point in the history
feat: double click to toggle fullscreen
feat: secondary click to toggle play state
  • Loading branch information
godly-devotion committed Mar 28, 2024
1 parent 141b62a commit e847002
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 38 deletions.
11 changes: 11 additions & 0 deletions Front Row/Support/PlayEngine.swift
Original file line number Diff line number Diff line change
Expand Up @@ -174,18 +174,25 @@ import SwiftUI

func cancelLoading() {
guard let asset else { return }

asset.cancelLoading()
}

func play() {
guard isLoaded else { return }

player.play()
}

func pause() {
guard isLoaded else { return }

player.pause()
}

func playPause() {
guard isLoaded else { return }

if timeControlStatus == .playing {
pause()
} else {
Expand All @@ -195,6 +202,7 @@ import SwiftUI

func goForwards(_ duration: Double = 5.0) async {
guard isLoaded else { return }

let time = CMTimeAdd(
player.currentTime(),
CMTimeMakeWithSeconds(duration, preferredTimescale: 1)
Expand All @@ -204,6 +212,7 @@ import SwiftUI

func goBackwards(_ duration: Double = 5.0) async {
guard isLoaded else { return }

let time = CMTimeSubtract(
player.currentTime(),
CMTimeMakeWithSeconds(duration, preferredTimescale: 1)
Expand All @@ -213,6 +222,7 @@ import SwiftUI

func goToTime(_ timecode: Double) async {
guard isLoaded else { return }

let time = CMTimeMakeWithSeconds(timecode, preferredTimescale: 1)
await player.seek(to: time, toleranceBefore: .zero, toleranceAfter: .zero)
}
Expand Down Expand Up @@ -244,6 +254,7 @@ import SwiftUI
func fitToVideoSize() {
guard videoSize != CGSize.zero else { return }
guard let window = NSApp.windows.first else { return }

let screenFrame = (window.screen ?? NSScreen.main!).visibleFrame
let newFrame: NSRect

Expand Down
44 changes: 23 additions & 21 deletions Front Row/Support/WindowController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,16 @@ import SwiftUI

static let shared = WindowController()

// MARK: - Fullscreen

private(set) var isFullscreen = false

func setIsFullscreen(_ isFullscreen: Bool) {
self.isFullscreen = isFullscreen
}

// MARK: - Float on Top

private var _isOnTop = false

var isOnTop: Bool {
Expand All @@ -27,10 +35,18 @@ import SwiftUI
}
}

func setIsFullscreen(_ isFullscreen: Bool) {
self.isFullscreen = isFullscreen
// MARK: - Autohide Cursor

func hideCursor() {
CGDisplayHideCursor(CGMainDisplayID())
}

func showCursor() {
CGDisplayShowCursor(CGMainDisplayID())
}

// MARK: - Autohide Titlebar

private var _titlebarView: NSView?

var titlebarView: NSView? {
Expand All @@ -42,23 +58,13 @@ import SwiftUI
.first(where: { $0.isKind(of: containerClass) })
else { return nil }

_titlebarView = containerView

return _titlebarView
}
guard let titlebarClass = NSClassFromString("NSTitlebarView") else { return nil }
guard let titlebar = containerView.subviews.first(where: { $0.isKind(of: titlebarClass) })
else { return nil }

private var mouseIdleTimer: Timer!
_titlebarView = titlebar

func resetMouseIdleTimer() {
if mouseIdleTimer != nil {
mouseIdleTimer.invalidate()
mouseIdleTimer = nil
}

mouseIdleTimer = Timer.scheduledTimer(withTimeInterval: 3.0, repeats: false) {
[weak self] in
self?.mouseIdleTimerAction($0)
}
return _titlebarView
}

func hideTitlebar() {
Expand All @@ -69,10 +75,6 @@ import SwiftUI
setTitlebarOpacity(1.0)
}

private func mouseIdleTimerAction(_ sender: Timer) {
hideTitlebar()
}

private func setTitlebarOpacity(_ opacity: CGFloat) {
/// when the window is in full screen, the titlebar view is in another window (the "toolbar window")
guard titlebarView?.window == NSApp.windows.first else { return }
Expand Down
41 changes: 24 additions & 17 deletions Front Row/Views/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ import SwiftUI

struct ContentView: View {
@Environment(PlayEngine.self) var playEngine: PlayEngine
@State private var playerControlsShown = true
@State private var mouseIdleTimer: Timer!
@State private var mouseInsideWindow = false
@State private var playerControlsShown = true

var body: some View {
@Bindable var playEngine = playEngine
Expand All @@ -37,13 +38,12 @@ struct ContentView: View {
}
)
)
.onTapGesture(count: 2) {
NSApplication.shared.mainWindow?.toggleFullScreen(nil)
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center)
.ignoresSafeArea()

if playEngine.timeControlStatus == .waitingToPlayAtSpecifiedRate {
if !playEngine.isLocalFile
&& playEngine.timeControlStatus == .waitingToPlayAtSpecifiedRate
{
ProgressView()
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center)
}
Expand All @@ -59,28 +59,20 @@ struct ContentView: View {
.onContinuousHover { phase in
switch phase {
case .active:
mouseInsideWindow = true
resetMouseIdleTimer()
showPlayerControls()
WindowController.shared.resetMouseIdleTimer()
WindowController.shared.showTitlebar()
WindowController.shared.showCursor()
case .ended:
mouseInsideWindow = false
hidePlayerControls()
WindowController.shared.hideTitlebar()
WindowController.shared.showCursor()
}
}
}

private func resetMouseIdleTimer() {
if mouseIdleTimer != nil {
mouseIdleTimer.invalidate()
mouseIdleTimer = nil
}

mouseIdleTimer = Timer.scheduledTimer(withTimeInterval: 3.0, repeats: false) {
mouseIdleTimerAction($0)
}
}

private func hidePlayerControls() {
withAnimation {
playerControlsShown = false
Expand All @@ -93,8 +85,23 @@ struct ContentView: View {
}
}

private func resetMouseIdleTimer() {
if mouseIdleTimer != nil {
mouseIdleTimer.invalidate()
mouseIdleTimer = nil
}

mouseIdleTimer = Timer.scheduledTimer(withTimeInterval: 3.0, repeats: false) {
mouseIdleTimerAction($0)
}
}

private func mouseIdleTimerAction(_ sender: Timer) {
hidePlayerControls()
WindowController.shared.hideTitlebar()
if mouseInsideWindow {
WindowController.shared.hideCursor()
}
}
}

Expand Down
14 changes: 14 additions & 0 deletions Front Row/Views/PlayerView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,26 @@ struct PlayerView: NSViewRepresentable {
let player: AVPlayer

class PlayerNSView: NSView, CALayerDelegate {

private let playerLayer = AVPlayerLayer()

override func makeBackingLayer() -> CALayer {
playerLayer
}

override func mouseDown(with event: NSEvent) {
if event.type == .leftMouseDown && event.clickCount == 2 {
NSApplication.shared.mainWindow?.toggleFullScreen(nil)
} else {
super.mouseDown(with: event)
}
}

override func rightMouseUp(with event: NSEvent) {
PlayEngine.shared.playPause()
super.rightMouseUp(with: event)
}

init(player: AVPlayer) {
super.init(frame: .zero)
playerLayer.player = player
Expand Down

0 comments on commit e847002

Please sign in to comment.