Skip to content

Commit

Permalink
Merge branch 'feat/detachable-window'
Browse files Browse the repository at this point in the history
  • Loading branch information
lukepistrol committed Feb 13, 2024
2 parents 69e910d + 6933903 commit 36ee469
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 13 deletions.
64 changes: 54 additions & 10 deletions TimeMachineStatus/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,16 @@ class AppDelegate: NSObject, NSApplicationDelegate {
var hostingView: NSHostingView<StatusBarItem>?
var popover: NSPopover?

lazy var detachedWindowController: DetachedWindowController = {
let menuView = MenuView(utility: utility, updater: updaterController.updater)
let windowController = DetachedWindowController(
window: .init(contentViewController: NSHostingController(
rootView: menuView
))
)
return windowController
}()

let utility: TMUtility = .init()

var updaterController: SPUStandardUpdaterController!
Expand Down Expand Up @@ -81,29 +91,44 @@ class AppDelegate: NSObject, NSApplicationDelegate {
if popover.isShown {
popover.performClose(sender)
} else {
popover.show(relativeTo: sender.bounds, of: sender, preferredEdge: .maxY)
// fixes popover not being fully visible on the right side of the screen
if let popoverFrame = popover.contentViewController?.view.window?.frame,
let screenFrame = popover.contentViewController?.view.window?.screen?.frame,
(popoverFrame.origin.x + Constants.Sizes.popoverWidth + 25) > screenFrame.width {
popover.contentViewController?.view.window?.setFrameOrigin(
NSPoint(x: screenFrame.width - Constants.Sizes.popoverWidth - 25, y: popoverFrame.origin.y)
)
if let detachedWindow = detachedWindowController.window, detachedWindow.isVisible {
detachedWindow.orderFrontRegardless()
} else {
popover.show(relativeTo: sender.bounds, of: sender, preferredEdge: .maxY)
// fixes popover not being fully visible on the right side of the screen
if let popoverFrame = popover.contentViewController?.view.window?.frame,
let screenFrame = popover.contentViewController?.view.window?.screen?.frame,
(popoverFrame.origin.x + Constants.Sizes.popoverWidth + 25) > screenFrame.width {
popover.contentViewController?.view.window?.setFrameOrigin(
NSPoint(x: screenFrame.width - Constants.Sizes.popoverWidth - 25, y: popoverFrame.origin.y)
)
}
popover.contentViewController?.view.window?.becomeKey()
}
popover.contentViewController?.view.window?.becomeKey()
}
}

private func setupPopover() {
let menuView = MenuView(utility: utility, updater: updaterController.updater)
popover = NSPopover()
popover?.delegate = self
popover?.contentViewController = NSHostingController(rootView: menuView)
popover?.animates = false
popover?.behavior = .applicationDefined
popover?.behavior = .semitransient
popover?.setValue(true, forKeyPath: "shouldHideAnchor") // hide arrow
}
}

extension AppDelegate: NSPopoverDelegate {
func popoverShouldDetach(_ popover: NSPopover) -> Bool {
return true
}

func detachableWindow(for popover: NSPopover) -> NSWindow? {
return detachedWindowController.window
}
}

extension AppDelegate: SPUStandardUserDriverDelegate {
var supportsGentleScheduledUpdateReminders: Bool {
return true
Expand All @@ -116,3 +141,22 @@ extension AppDelegate: SPUStandardUserDriverDelegate {
return true
}
}

class DetachedWindowController: NSWindowController {
init(window: NSWindow) {
super.init(window: window)

window.styleMask = [
.closable,
.titled,
.fullSizeContentView
]
window.titlebarAppearsTransparent = true
window.standardWindowButton(.miniaturizeButton)?.isHidden = true
window.standardWindowButton(.zoomButton)?.isHidden = true
}

required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
23 changes: 23 additions & 0 deletions TimeMachineStatus/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -1726,6 +1726,29 @@
}
}
}
},
"window_title" : {
"extractionState" : "manual",
"localizations" : {
"de" : {
"stringUnit" : {
"state" : "translated",
"value" : "TimeMachineStatus"
}
},
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "TimeMachineStatus"
}
},
"it" : {
"stringUnit" : {
"state" : "translated",
"value" : "TimeMachineStatus"
}
}
}
}
},
"version" : "1.0"
Expand Down
5 changes: 2 additions & 3 deletions TimeMachineStatus/Views/MenuView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ struct MenuView: View {
}
.frame(width: Constants.Sizes.popoverWidth)
.fixedSize()
.navigationTitle("window_title")
.background(.regularMaterial, in: .rect)
}

@ViewBuilder
Expand Down Expand Up @@ -207,18 +209,15 @@ struct MenuView: View {
Button("settings_button_checkforupdates") {
updater.checkForUpdates()
}
.keyboardShortcut("u", modifiers: .command)
.disabled(!updaterViewModel.canCheckForUpdates)
Button("button_browsebackups") {
utility.launchTimeMachine()
}
.keyboardShortcut("b", modifiers: .command)
Divider()
Menu("button_feedback") {
Button("button_bug_report_feature_request") {
NSWorkspace.shared.open(Constants.URLs.bugReport)
}
.keyboardShortcut("f", modifiers: .command)
Divider()
Button("button_view_issues") {
NSWorkspace.shared.open(Constants.URLs.issues)
Expand Down

0 comments on commit 36ee469

Please sign in to comment.