Fix macOS Swift warnings
parent
46d54ed673
commit
7b17c588c6
|
|
@ -136,7 +136,7 @@ struct CommandPaletteView: View {
|
|||
break
|
||||
}
|
||||
}
|
||||
.onChange(of: query) { newValue in
|
||||
.backport.onChange(of: query) { newValue in
|
||||
// If the user types a query then we want to make sure the first
|
||||
// value is selected. If the user clears the query and we were selecting
|
||||
// the first, we unset any selection.
|
||||
|
|
@ -181,7 +181,7 @@ struct CommandPaletteView: View {
|
|||
.shadow(radius: 32, x: 0, y: 12)
|
||||
.padding()
|
||||
.environment(\.colorScheme, scheme)
|
||||
.onChange(of: isPresented) { newValue in
|
||||
.backport.onChange(of: isPresented) { newValue in
|
||||
if !newValue {
|
||||
// This is optional, since most of the time
|
||||
// there will be a delay before the next use.
|
||||
|
|
@ -261,7 +261,7 @@ private struct CommandPaletteQuery: View {
|
|||
.frame(height: 48)
|
||||
.textFieldStyle(.plain)
|
||||
.focused($isTextFieldFocused)
|
||||
.onChange(of: isTextFieldFocused) { focused in
|
||||
.backport.onChange(of: isTextFieldFocused) { focused in
|
||||
if !focused {
|
||||
onEvent?(.exit)
|
||||
}
|
||||
|
|
@ -322,7 +322,7 @@ private struct CommandTable: View {
|
|||
.padding(10)
|
||||
}
|
||||
.frame(maxHeight: 200)
|
||||
.onChange(of: selectedIndex) { _ in
|
||||
.backport.onChange(of: selectedIndex) {
|
||||
guard let selectedIndex,
|
||||
selectedIndex < options.count else { return }
|
||||
proxy.scrollTo(
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ struct TerminalCommandPaletteView: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
.onChange(of: isPresented) { newValue in
|
||||
.backport.onChange(of: isPresented) { newValue in
|
||||
// When the command palette disappears we need to send focus back to the
|
||||
// surface view we were overlaid on top of. There's probably a better way
|
||||
// to handle the first responder state here but I don't know it.
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ struct TerminalView<ViewModel: TerminalViewModel>: View {
|
|||
.ghosttyLastFocusedSurface(lastFocusedSurface)
|
||||
.focused($focused)
|
||||
.onAppear { self.focused = true }
|
||||
.onChange(of: focusedSurface) { newValue in
|
||||
.backport.onChange(of: focusedSurface) { newValue in
|
||||
// We want to keep track of our last focused surface so even if
|
||||
// we lose focus we keep this set to the last non-nil value.
|
||||
if newValue != nil {
|
||||
|
|
@ -94,10 +94,10 @@ struct TerminalView<ViewModel: TerminalViewModel>: View {
|
|||
self.delegate?.focusedSurfaceDidChange(to: newValue)
|
||||
}
|
||||
}
|
||||
.onChange(of: pwdURL) { newValue in
|
||||
.backport.onChange(of: pwdURL) { newValue in
|
||||
self.delegate?.pwdDidChange(to: newValue)
|
||||
}
|
||||
.onChange(of: cellSize) { newValue in
|
||||
.backport.onChange(of: cellSize) { newValue in
|
||||
guard let size = newValue else { return }
|
||||
self.delegate?.cellSizeDidChange(to: size)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ struct UpdatePill: View {
|
|||
UpdatePopoverView(model: model)
|
||||
}
|
||||
.transition(.opacity.combined(with: .scale(scale: 0.95)))
|
||||
.onChange(of: model.state) { newState in
|
||||
.backport.onChange(of: model.state) { newState in
|
||||
resetTask?.cancel()
|
||||
if case .notFound(let notFound) = newState {
|
||||
resetTask = Task { [weak model] in
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ extension Ghostty {
|
|||
/// Represents the inspector for a surface within Ghostty.
|
||||
///
|
||||
/// Wraps a `ghostty_inspector_t`
|
||||
final class Inspector: Sendable {
|
||||
final class Inspector: @unchecked Sendable {
|
||||
private let inspector: ghostty_inspector_t
|
||||
|
||||
/// Read the underlying C value for this inspector. This is unsafe because the value will be
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ extension Ghostty {
|
|||
/// all over.
|
||||
///
|
||||
/// Wraps a `ghostty_surface_t`
|
||||
final class Surface: Sendable {
|
||||
final class Surface: @unchecked Sendable {
|
||||
private let surface: ghostty_surface_t
|
||||
|
||||
/// Read the underlying C value for this surface. This is unsafe because the value will be
|
||||
|
|
|
|||
|
|
@ -7,10 +7,6 @@ import GhosttyKit
|
|||
/// A command is fully self-contained so it is Sendable.
|
||||
extension ghostty_command_s: @unchecked @retroactive Sendable {}
|
||||
|
||||
/// A surface is sendable because it is just a reference type. Using the surface in parameters
|
||||
/// may be unsafe but the value itself is safe to send across threads.
|
||||
extension ghostty_surface_t: @unchecked @retroactive Sendable {}
|
||||
|
||||
extension Ghostty {
|
||||
// The user notification category identifier
|
||||
static let userNotificationCategory = "com.mitchellh.ghostty.userNotification"
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ extension Ghostty {
|
|||
}
|
||||
}
|
||||
.onReceive(pubInspector) { onControlInspector($0) }
|
||||
.onChange(of: surfaceView.inspectorVisible) { inspectorVisible in
|
||||
.backport.onChange(of: surfaceView.inspectorVisible) { inspectorVisible in
|
||||
// When we show the inspector, we want to focus on the inspector.
|
||||
// When we hide the inspector, we want to move focus back to the surface.
|
||||
if inspectorVisible {
|
||||
|
|
|
|||
|
|
@ -937,7 +937,7 @@ extension Ghostty {
|
|||
.opacity(dotOpacity(for: index))
|
||||
}
|
||||
}
|
||||
.onChange(of: context.date.timeIntervalSinceReferenceDate) { newValue in
|
||||
.backport.onChange(of: context.date.timeIntervalSinceReferenceDate) { newValue in
|
||||
animationPhase = newValue
|
||||
}
|
||||
}
|
||||
|
|
@ -1011,7 +1011,7 @@ extension Ghostty {
|
|||
.allowsHitTesting(false)
|
||||
.opacity(highlighted ? 1.0 : 0.0)
|
||||
.animation(.easeOut(duration: 0.4), value: highlighted)
|
||||
.onChange(of: highlighted) { newValue in
|
||||
.backport.onChange(of: highlighted) { newValue in
|
||||
if newValue {
|
||||
withAnimation(.easeInOut(duration: 0.4).repeatForever(autoreverses: true)) {
|
||||
borderPulse = true
|
||||
|
|
|
|||
|
|
@ -1726,27 +1726,31 @@ extension Ghostty {
|
|||
trigger: nil
|
||||
)
|
||||
|
||||
// Note the callback may be executed on a background thread as documented
|
||||
// so we need @MainActor since we're reading/writing view state.
|
||||
UNUserNotificationCenter.current().add(request) { @MainActor error in
|
||||
// Note the callback may be executed on a background thread as documented,
|
||||
// so view state is updated from an explicit main-actor task below.
|
||||
UNUserNotificationCenter.current().add(request) { [weak self, uuid] error in
|
||||
if let error = error {
|
||||
AppDelegate.logger.error("Error scheduling user notification: \(error)")
|
||||
return
|
||||
}
|
||||
|
||||
// We need to keep track of this notification so we can remove it
|
||||
// under certain circumstances
|
||||
self.notificationIdentifiers.insert(uuid)
|
||||
Task { @MainActor [weak self, uuid] in
|
||||
guard let self else { return }
|
||||
|
||||
// If we're focused then we schedule to remove the notification
|
||||
// after a few seconds. If we gain focus we automatically remove it
|
||||
// in focusDidChange.
|
||||
if self.focused {
|
||||
Task { @MainActor [weak self] in
|
||||
try await Task.sleep(for: .seconds(3))
|
||||
self?.notificationIdentifiers.remove(uuid)
|
||||
UNUserNotificationCenter.current()
|
||||
.removeDeliveredNotifications(withIdentifiers: [uuid])
|
||||
// We need to keep track of this notification so we can remove it
|
||||
// under certain circumstances.
|
||||
self.notificationIdentifiers.insert(uuid)
|
||||
|
||||
// If we're focused then we schedule to remove the notification
|
||||
// after a few seconds. If we gain focus we automatically remove it
|
||||
// in focusDidChange.
|
||||
if self.focused {
|
||||
Task { @MainActor [weak self, uuid] in
|
||||
try await Task.sleep(for: .seconds(3))
|
||||
self?.notificationIdentifiers.remove(uuid)
|
||||
UNUserNotificationCenter.current()
|
||||
.removeDeliveredNotifications(withIdentifiers: [uuid])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,39 @@ enum BackportKeyPressResult {
|
|||
}
|
||||
|
||||
extension Backport where Content: View {
|
||||
/// Backported onChange that uses the modern two-parameter closure on
|
||||
/// platforms that provide it while preserving macOS 13 support.
|
||||
func onChange<Value: Equatable>(
|
||||
of value: Value,
|
||||
_ action: @escaping (Value) -> Void
|
||||
) -> some View {
|
||||
if #available(iOS 17, macOS 14, *) {
|
||||
return content.onChange(of: value) { _, newValue in
|
||||
action(newValue)
|
||||
}
|
||||
} else {
|
||||
return content.onChange(of: value) { newValue in
|
||||
action(newValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Backported onChange variant for handlers that do not need the new value.
|
||||
func onChange<Value: Equatable>(
|
||||
of value: Value,
|
||||
_ action: @escaping () -> Void
|
||||
) -> some View {
|
||||
if #available(iOS 17, macOS 14, *) {
|
||||
return content.onChange(of: value) { _, _ in
|
||||
action()
|
||||
}
|
||||
} else {
|
||||
return content.onChange(of: value) { _ in
|
||||
action()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func pointerVisibility(_ v: BackportVisibility) -> some View {
|
||||
#if canImport(AppKit)
|
||||
if #available(macOS 15, *) {
|
||||
|
|
|
|||
|
|
@ -47,6 +47,8 @@ extension KeyboardShortcut: @retroactive CustomStringConvertible {
|
|||
}
|
||||
|
||||
// This is available in macOS 14 so this only applies to early macOS versions.
|
||||
@available(macOS, introduced: 10.15, obsoleted: 14.0)
|
||||
@available(iOS, introduced: 13.0, obsoleted: 17.0)
|
||||
extension KeyEquivalent: @retroactive Equatable {
|
||||
public static func == (lhs: KeyEquivalent, rhs: KeyEquivalent) -> Bool {
|
||||
lhs.character == rhs.character
|
||||
|
|
|
|||
Loading…
Reference in New Issue