Improve update UI error details

This commit is contained in:
Lawrence Chen 2026-01-28 01:49:02 -08:00
parent 17a3e2033f
commit 0441efc675
18 changed files with 915 additions and 82 deletions

View file

@ -1,4 +1,5 @@
import AppKit
import Combine
import SwiftUI
final class WindowToolbarController: NSObject, NSToolbarDelegate {
@ -10,6 +11,8 @@ final class WindowToolbarController: NSObject, NSToolbarDelegate {
private var commandLabels: [ObjectIdentifier: NSTextField] = [:]
private var observers: [NSObjectProtocol] = []
private var updateSizeCancellables: [ObjectIdentifier: AnyCancellable] = [:]
private var updateViewConstraints: [ObjectIdentifier: (width: NSLayoutConstraint, height: NSLayoutConstraint)] = [:]
init(updateViewModel: UpdateViewModel) {
self.updateViewModel = updateViewModel
@ -20,6 +23,9 @@ final class WindowToolbarController: NSObject, NSToolbarDelegate {
for observer in observers {
NotificationCenter.default.removeObserver(observer)
}
for cancellable in updateSizeCancellables.values {
cancellable.cancel()
}
}
func start(tabManager: TabManager) {
@ -68,12 +74,13 @@ final class WindowToolbarController: NSObject, NSToolbarDelegate {
let toolbar = NSToolbar(identifier: NSToolbar.Identifier("cmux.toolbar"))
toolbar.delegate = self
toolbar.displayMode = .iconOnly
toolbar.sizeMode = .small
toolbar.allowsUserCustomization = false
toolbar.autosavesConfiguration = false
toolbar.showsBaselineSeparator = false
window.toolbar = toolbar
window.toolbarStyle = .unified
window.titleVisibility = .visible
window.toolbarStyle = .unifiedCompact
window.titleVisibility = .hidden
}
private func updateFocusedCommandText() {
@ -118,18 +125,39 @@ final class WindowToolbarController: NSObject, NSToolbarDelegate {
if itemIdentifier == updateItemIdentifier, let updateViewModel {
let item = NSToolbarItem(itemIdentifier: itemIdentifier)
let view = NonDraggableHostingView(rootView: UpdatePill(
model: updateViewModel,
showWhenIdle: true,
onIdleTap: {
guard let delegate = NSApp.delegate as? AppDelegate else { return }
delegate.checkForUpdates(nil)
}
))
let view = NonDraggableHostingView(rootView: UpdatePill(model: updateViewModel))
let key = ObjectIdentifier(toolbar)
item.view = view
sizeToolbarItem(for: key, hostingView: view)
updateSizeCancellables[key]?.cancel()
updateSizeCancellables[key] = updateViewModel.$state
.receive(on: DispatchQueue.main)
.sink { [weak self, weak view] _ in
guard let self, let view else { return }
self.sizeToolbarItem(for: key, hostingView: view)
}
return item
}
return nil
}
private func sizeToolbarItem(for key: ObjectIdentifier, hostingView: NSView) {
hostingView.invalidateIntrinsicContentSize()
hostingView.layoutSubtreeIfNeeded()
let size = hostingView.fittingSize
hostingView.setFrameSize(size)
hostingView.setContentHuggingPriority(.required, for: .horizontal)
hostingView.setContentHuggingPriority(.required, for: .vertical)
hostingView.translatesAutoresizingMaskIntoConstraints = false
if let constraints = updateViewConstraints[key] {
constraints.width.constant = size.width
constraints.height.constant = size.height
} else {
let width = hostingView.widthAnchor.constraint(equalToConstant: size.width)
let height = hostingView.heightAnchor.constraint(equalToConstant: size.height)
NSLayoutConstraint.activate([width, height])
updateViewConstraints[key] = (width: width, height: height)
}
}
}