Improve windows handling on macOS

This commit is contained in:
Arkadiusz Fal 2022-01-06 16:35:45 +01:00
parent 3baa7a6893
commit 8a74938b98
7 changed files with 91 additions and 59 deletions

View File

@ -50,7 +50,7 @@ final class NavigationModel: ObservableObject {
) { ) {
let recent = RecentItem(from: channel) let recent = RecentItem(from: channel)
#if os(macOS) #if os(macOS)
OpenWindow.main.open() Windows.main.open()
#else #else
player.hide() player.hide()
#endif #endif

View File

@ -33,7 +33,7 @@ final class PlayerModel: ObservableObject {
@Published var streamSelection: Stream? { didSet { rebuildTVMenu() } } @Published var streamSelection: Stream? { didSet { rebuildTVMenu() } }
@Published var queue = [PlayerQueueItem]() { didSet { Defaults[.queue] = queue } } @Published var queue = [PlayerQueueItem]() { didSet { Defaults[.queue] = queue } }
@Published var currentItem: PlayerQueueItem! @Published var currentItem: PlayerQueueItem! { didSet { updateWindowTitle() }}
@Published var historyVideos = [Video]() @Published var historyVideos = [Video]()
@Published var preservedTime: CMTime? @Published var preservedTime: CMTime?
@ -103,13 +103,13 @@ final class PlayerModel: ObservableObject {
func show() { func show() {
guard !presentingPlayer else { guard !presentingPlayer else {
#if os(macOS) #if os(macOS)
OpenWindow.player.focus() Windows.player.focus()
#endif #endif
return return
} }
#if os(macOS) #if os(macOS)
OpenWindow.player.open() Windows.player.open()
OpenWindow.player.focus() Windows.player.focus()
#endif #endif
presentingPlayer = true presentingPlayer = true
} }
@ -122,9 +122,9 @@ final class PlayerModel: ObservableObject {
func togglePlayer() { func togglePlayer() {
#if os(macOS) #if os(macOS)
if !presentingPlayer { if !presentingPlayer {
OpenWindow.player.open() Windows.player.open()
} }
OpenWindow.player.focus() Windows.player.focus()
#else #else
if presentingPlayer { if presentingPlayer {
hide() hide()
@ -804,6 +804,12 @@ final class PlayerModel: ObservableObject {
} }
#endif #endif
func updateWindowTitle() {
#if os(macOS)
Windows.player.window?.title = windowTitle
#endif
}
#if os(macOS) #if os(macOS)
var windowTitle: String { var windowTitle: String {
currentVideo.isNil ? "Not playing" : "\(currentVideo!.title) - \(currentVideo!.author)" currentVideo.isNil ? "Not playing" : "\(currentVideo!.title) - \(currentVideo!.author)"

View File

@ -14,7 +14,7 @@ struct OpenURLHandler {
} }
#if os(macOS) #if os(macOS)
guard url.host != OpenWindow.player.location else { guard url.host != Windows.player.location else {
return return
} }
#endif #endif
@ -28,7 +28,7 @@ struct OpenURLHandler {
} }
#if os(macOS) #if os(macOS)
OpenWindow.main.open() Windows.main.open()
#endif #endif
accounts.api.video(id).load().onSuccess { response in accounts.api.video(id).load().onSuccess { response in

View File

@ -47,12 +47,18 @@ struct YatteeApp: App {
.environmentObject(thumbnails) .environmentObject(thumbnails)
.environmentObject(menu) .environmentObject(menu)
.environmentObject(search) .environmentObject(search)
#if !os(macOS) #if os(macOS)
.onReceive( .background(
NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification) HostingWindowFinder { window in
) { _ in Windows.mainWindow = window
player.handleEnterForeground() }
} )
#else
.onReceive(
NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)
) { _ in
player.handleEnterForeground()
}
#endif #endif
#if os(iOS) #if os(iOS)
.handlesExternalEvents(preferring: Set(["*"]), allowing: Set(["*"])) .handlesExternalEvents(preferring: Set(["*"]), allowing: Set(["*"]))
@ -81,6 +87,11 @@ struct YatteeApp: App {
#if os(macOS) #if os(macOS)
WindowGroup(player.windowTitle) { WindowGroup(player.windowTitle) {
VideoPlayerView() VideoPlayerView()
.background(
HostingWindowFinder { window in
Windows.playerWindow = window
}
)
.onAppear { player.presentingPlayer = true } .onAppear { player.presentingPlayer = true }
.onDisappear { player.presentingPlayer = false } .onDisappear { player.presentingPlayer = false }
.environment(\.managedObjectContext, persistenceController.container.viewContext) .environment(\.managedObjectContext, persistenceController.container.viewContext)

View File

@ -240,7 +240,7 @@
37732FF22703A26300F04329 /* AccountValidationStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37732FEF2703A26300F04329 /* AccountValidationStatus.swift */; }; 37732FF22703A26300F04329 /* AccountValidationStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37732FEF2703A26300F04329 /* AccountValidationStatus.swift */; };
37732FF42703D32400F04329 /* Sidebar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37732FF32703D32400F04329 /* Sidebar.swift */; }; 37732FF42703D32400F04329 /* Sidebar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37732FF32703D32400F04329 /* Sidebar.swift */; };
37732FF52703D32400F04329 /* Sidebar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37732FF32703D32400F04329 /* Sidebar.swift */; }; 37732FF52703D32400F04329 /* Sidebar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37732FF32703D32400F04329 /* Sidebar.swift */; };
37737786276F9858000521C1 /* OpenWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37737785276F9858000521C1 /* OpenWindow.swift */; }; 37737786276F9858000521C1 /* Windows.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37737785276F9858000521C1 /* Windows.swift */; };
3774122A27387B6C00423605 /* InstancesModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3774122927387B6C00423605 /* InstancesModelTests.swift */; }; 3774122A27387B6C00423605 /* InstancesModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3774122927387B6C00423605 /* InstancesModelTests.swift */; };
3774122F27387C7600423605 /* VideosApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 376A33DF2720CAD6000C1D6B /* VideosApp.swift */; }; 3774122F27387C7600423605 /* VideosApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 376A33DF2720CAD6000C1D6B /* VideosApp.swift */; };
3774123327387CB000423605 /* Defaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 372915E52687E3B900F5A35B /* Defaults.swift */; }; 3774123327387CB000423605 /* Defaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 372915E52687E3B900F5A35B /* Defaults.swift */; };
@ -690,7 +690,7 @@
376CD21526FBE18D001E1AC1 /* Instance+Fixtures.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Instance+Fixtures.swift"; sourceTree = "<group>"; }; 376CD21526FBE18D001E1AC1 /* Instance+Fixtures.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Instance+Fixtures.swift"; sourceTree = "<group>"; };
37732FEF2703A26300F04329 /* AccountValidationStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountValidationStatus.swift; sourceTree = "<group>"; }; 37732FEF2703A26300F04329 /* AccountValidationStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountValidationStatus.swift; sourceTree = "<group>"; };
37732FF32703D32400F04329 /* Sidebar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sidebar.swift; sourceTree = "<group>"; }; 37732FF32703D32400F04329 /* Sidebar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sidebar.swift; sourceTree = "<group>"; };
37737785276F9858000521C1 /* OpenWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenWindow.swift; sourceTree = "<group>"; }; 37737785276F9858000521C1 /* Windows.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Windows.swift; sourceTree = "<group>"; };
3774122927387B6C00423605 /* InstancesModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstancesModelTests.swift; sourceTree = "<group>"; }; 3774122927387B6C00423605 /* InstancesModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstancesModelTests.swift; sourceTree = "<group>"; };
377A20A82693C9A2002842B8 /* TypedContentAccessors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TypedContentAccessors.swift; sourceTree = "<group>"; }; 377A20A82693C9A2002842B8 /* TypedContentAccessors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TypedContentAccessors.swift; sourceTree = "<group>"; };
3782B94E27553A6700990149 /* SearchSuggestions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchSuggestions.swift; sourceTree = "<group>"; }; 3782B94E27553A6700990149 /* SearchSuggestions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchSuggestions.swift; sourceTree = "<group>"; };
@ -1182,7 +1182,7 @@
37BE7AF227601DBF00DBECED /* Updates */, 37BE7AF227601DBF00DBECED /* Updates */,
374C0542272496E4009BDDBE /* AppDelegate.swift */, 374C0542272496E4009BDDBE /* AppDelegate.swift */,
37FD43DB270470B70073EE42 /* InstancesSettings.swift */, 37FD43DB270470B70073EE42 /* InstancesSettings.swift */,
37737785276F9858000521C1 /* OpenWindow.swift */, 37737785276F9858000521C1 /* Windows.swift */,
374108D0272B11B2006C5CC8 /* PictureInPictureDelegate.swift */, 374108D0272B11B2006C5CC8 /* PictureInPictureDelegate.swift */,
37BE0BDB26A2367F0092E2DB /* Player.swift */, 37BE0BDB26A2367F0092E2DB /* Player.swift */,
37BE0BD926A214630092E2DB /* PlayerViewController.swift */, 37BE0BD926A214630092E2DB /* PlayerViewController.swift */,
@ -2060,7 +2060,7 @@
374710062755291C00CE0F87 /* SearchField.swift in Sources */, 374710062755291C00CE0F87 /* SearchField.swift in Sources */,
378AE93F274EDFB5006A4EE1 /* Tint+Backport.swift in Sources */, 378AE93F274EDFB5006A4EE1 /* Tint+Backport.swift in Sources */,
37C194C826F6A9C8005D3B96 /* RecentsModel.swift in Sources */, 37C194C826F6A9C8005D3B96 /* RecentsModel.swift in Sources */,
37737786276F9858000521C1 /* OpenWindow.swift in Sources */, 37737786276F9858000521C1 /* Windows.swift in Sources */,
37BE0BDC26A2367F0092E2DB /* Player.swift in Sources */, 37BE0BDC26A2367F0092E2DB /* Player.swift in Sources */,
3743CA53270F284F00E4D32B /* View+Borders.swift in Sources */, 3743CA53270F284F00E4D32B /* View+Borders.swift in Sources */,
37599F39272B4D740087F250 /* FavoriteButton.swift in Sources */, 37599F39272B4D740087F250 /* FavoriteButton.swift in Sources */,

View File

@ -1,40 +0,0 @@
import AppKit
import Foundation
enum OpenWindow: String, CaseIterable {
case player, main
var window: NSWindow? {
// this is not solid but works as long as there is only two windows in the app
// needs to be changed in case we ever have more windows to handle
switch self {
case .player:
return NSApplication.shared.windows.last
case .main:
return NSApplication.shared.windows.first
}
}
func focus() {
window?.makeKeyAndOrderFront(self)
}
var location: String {
switch self {
case .player:
return rawValue
case .main:
return ""
}
}
func open() {
switch self {
case .player:
NSWorkspace.shared.open(URL(string: "yattee://\(location)")!)
case .main:
Self.main.focus()
}
}
}

55
macOS/Windows.swift Normal file
View File

@ -0,0 +1,55 @@
import AppKit
import Foundation
import SwiftUI
enum Windows: String, CaseIterable {
case player, main
static var mainWindow: NSWindow?
static var playerWindow: NSWindow?
weak var window: NSWindow? {
switch self {
case .player:
return Self.playerWindow
case .main:
return Self.mainWindow
}
}
func focus() {
window?.makeKeyAndOrderFront(self)
}
var location: String {
switch self {
case .player:
return rawValue
case .main:
return ""
}
}
func open() {
switch self {
case .player:
NSWorkspace.shared.open(URL(string: "yattee://\(location)")!)
case .main:
Self.main.focus()
}
}
}
struct HostingWindowFinder: NSViewRepresentable {
var callback: (NSWindow?) -> Void
func makeNSView(context _: Self.Context) -> NSView {
let view = NSView()
DispatchQueue.main.async { [weak view] in
self.callback(view?.window)
}
return view
}
func updateNSView(_: NSView, context _: Context) {}
}