mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-06-03 10:24:51 +00:00
macOS: stop cycling icons when AboutWindow is closed
and start cycling with current icon
This commit is contained in:
@@ -117,6 +117,7 @@
|
||||
Features/About/About.xib,
|
||||
Features/About/AboutController.swift,
|
||||
Features/About/AboutView.swift,
|
||||
Features/About/AboutViewModel.swift,
|
||||
Features/About/CyclingIconView.swift,
|
||||
"Features/App Intents/CloseTerminalIntent.swift",
|
||||
"Features/App Intents/CommandPaletteIntent.swift",
|
||||
|
||||
@@ -5,19 +5,21 @@ import SwiftUI
|
||||
class AboutController: NSWindowController, NSWindowDelegate {
|
||||
static let shared: AboutController = AboutController()
|
||||
|
||||
private let viewModel = AboutViewModel()
|
||||
override var windowNibName: NSNib.Name? { "About" }
|
||||
|
||||
override func windowDidLoad() {
|
||||
guard let window = window else { return }
|
||||
window.center()
|
||||
window.isMovableByWindowBackground = true
|
||||
window.contentView = NSHostingView(rootView: AboutView())
|
||||
window.contentView = NSHostingView(rootView: AboutView().environmentObject(viewModel))
|
||||
}
|
||||
|
||||
// MARK: - Functions
|
||||
|
||||
func show() {
|
||||
window?.makeKeyAndOrderFront(nil)
|
||||
viewModel.startCyclingIcons()
|
||||
}
|
||||
|
||||
func hide() {
|
||||
@@ -38,4 +40,8 @@ class AboutController: NSWindowController, NSWindowDelegate {
|
||||
@objc func cancel(_ sender: Any?) {
|
||||
close()
|
||||
}
|
||||
|
||||
func windowWillClose(_ notification: Notification) {
|
||||
viewModel.stopCyclingIcons()
|
||||
}
|
||||
}
|
||||
|
||||
40
macos/Sources/Features/About/AboutViewModel.swift
Normal file
40
macos/Sources/Features/About/AboutViewModel.swift
Normal file
@@ -0,0 +1,40 @@
|
||||
import Combine
|
||||
|
||||
class AboutViewModel: ObservableObject {
|
||||
@Published var currentIcon: Ghostty.MacOSIcon?
|
||||
@Published var isHovering: Bool = false
|
||||
|
||||
private var timerCancellable: AnyCancellable?
|
||||
|
||||
private let icons: [Ghostty.MacOSIcon] = [
|
||||
.official,
|
||||
.blueprint,
|
||||
.chalkboard,
|
||||
.microchip,
|
||||
.glass,
|
||||
.holographic,
|
||||
.paper,
|
||||
.retro,
|
||||
.xray,
|
||||
]
|
||||
|
||||
func startCyclingIcons() {
|
||||
timerCancellable = Timer.publish(every: 3, on: .main, in: .common)
|
||||
.autoconnect()
|
||||
.sink { [weak self] _ in
|
||||
guard let self, !isHovering else { return }
|
||||
advanceToNextIcon()
|
||||
}
|
||||
}
|
||||
|
||||
func stopCyclingIcons() {
|
||||
timerCancellable = nil
|
||||
currentIcon = nil
|
||||
}
|
||||
|
||||
func advanceToNextIcon() {
|
||||
let currentIndex = currentIcon.flatMap(icons.firstIndex(of:)) ?? 0
|
||||
let nextIndex = icons.indexWrapping(after: currentIndex)
|
||||
currentIcon = icons[nextIndex]
|
||||
}
|
||||
}
|
||||
@@ -1,50 +1,38 @@
|
||||
import SwiftUI
|
||||
import GhosttyKit
|
||||
import Combine
|
||||
|
||||
/// A view that cycles through Ghostty's official icon variants.
|
||||
struct CyclingIconView: View {
|
||||
@State private var currentIcon: Ghostty.MacOSIcon = .official
|
||||
@State private var isHovering: Bool = false
|
||||
|
||||
private let icons: [Ghostty.MacOSIcon] = [
|
||||
.official,
|
||||
.blueprint,
|
||||
.chalkboard,
|
||||
.microchip,
|
||||
.glass,
|
||||
.holographic,
|
||||
.paper,
|
||||
.retro,
|
||||
.xray,
|
||||
]
|
||||
private let timerPublisher = Timer.publish(every: 3, on: .main, in: .common)
|
||||
@EnvironmentObject var viewModel: AboutViewModel
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
iconView(for: currentIcon)
|
||||
.id(currentIcon)
|
||||
iconView(for: viewModel.currentIcon)
|
||||
.id(viewModel.currentIcon)
|
||||
}
|
||||
.animation(.easeInOut(duration: 0.5), value: currentIcon)
|
||||
.animation(.easeInOut(duration: 0.5), value: viewModel.currentIcon)
|
||||
.frame(height: 128)
|
||||
.onReceive(timerPublisher.autoconnect()) { _ in
|
||||
if !isHovering {
|
||||
advanceToNextIcon()
|
||||
}
|
||||
}
|
||||
.onHover { hovering in
|
||||
isHovering = hovering
|
||||
viewModel.isHovering = hovering
|
||||
}
|
||||
.onTapGesture {
|
||||
advanceToNextIcon()
|
||||
viewModel.advanceToNextIcon()
|
||||
}
|
||||
.contextMenu {
|
||||
if let currentIcon = viewModel.currentIcon {
|
||||
Button("Copy Icon Config") {
|
||||
NSPasteboard.general.setString("macos-icon = \(currentIcon.rawValue)", forType: .string)
|
||||
}
|
||||
}
|
||||
}
|
||||
.help("macos-icon = \(currentIcon.rawValue)")
|
||||
.accessibilityLabel("Ghostty Application Icon")
|
||||
.accessibilityHint("Click to cycle through icon variants")
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private func iconView(for icon: Ghostty.MacOSIcon) -> some View {
|
||||
let iconImage: Image = switch icon.assetName {
|
||||
private func iconView(for icon: Ghostty.MacOSIcon?) -> some View {
|
||||
let iconImage: Image = switch icon?.assetName {
|
||||
case let assetName?: Image(assetName)
|
||||
case nil: ghosttyIconImage()
|
||||
}
|
||||
@@ -53,10 +41,4 @@ struct CyclingIconView: View {
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
}
|
||||
|
||||
private func advanceToNextIcon() {
|
||||
let currentIndex = icons.firstIndex(of: currentIcon) ?? 0
|
||||
let nextIndex = icons.indexWrapping(after: currentIndex)
|
||||
currentIcon = icons[nextIndex]
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user