mirror of
https://github.com/yattee/yattee.git
synced 2024-12-22 21:43:41 +00:00
Improve windows handling on macOS
This commit is contained in:
parent
3baa7a6893
commit
8a74938b98
@ -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
|
||||||
|
@ -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)"
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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 */,
|
||||||
|
@ -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
55
macOS/Windows.swift
Normal 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) {}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user