Fix: Caps Lock View

This commit is contained in:
Hariharan Mudaliar 2026-01-08 23:16:34 +05:30
commit 168dc27af5
No known key found for this signature in database
GPG key ID: 025583EB0BE5640E
6 changed files with 100 additions and 38 deletions

View file

@ -485,10 +485,14 @@ struct ContentView: View {
.frame(height: vm.effectiveClosedNotchHeight + (isHovering ? 8 : 0), alignment: .center)
} else if coordinator.sneakPeek.show && Defaults[.inlineHUD] && (coordinator.sneakPeek.type != .music) && (coordinator.sneakPeek.type != .battery) && (coordinator.sneakPeek.type != .timer) && (coordinator.sneakPeek.type != .reminder) && (coordinator.sneakPeek.type != .volume || vm.notchState == .closed) {
InlineHUD(type: $coordinator.sneakPeek.type, value: $coordinator.sneakPeek.value, icon: $coordinator.sneakPeek.icon, hoverAnimation: $isHovering, gestureProgress: $gestureProgress)
.transition(.opacity)
.transition(
coordinator.sneakPeek.type == .capsLock
? .move(edge: .trailing).combined(with: .opacity)
: .opacity
)
} else if vm.notchState == .closed && capsLockManager.isCapsLockActive && Defaults[.enableCapsLockIndicator] && !vm.hideOnClosed && !lockScreenManager.isLocked {
InlineHUD(type: .constant(.capsLock), value: .constant(1.0), icon: .constant(""), hoverAnimation: $isHovering, gestureProgress: $gestureProgress)
.transition(.opacity)
.transition(.move(edge: .trailing).combined(with: .opacity))
} else if (!coordinator.expandingView.show || coordinator.expandingView.type == .music) && vm.notchState == .closed && (musicManager.isPlaying || !musicManager.isPlayerIdle) && coordinator.musicLiveActivityEnabled && !vm.hideOnClosed && !lockScreenManager.isLocked {
MusicLiveActivity()
} else if (!coordinator.expandingView.show || coordinator.expandingView.type == .timer) && vm.notchState == .closed && timerManager.isTimerActive && coordinator.timerLiveActivityEnabled && !vm.hideOnClosed {

View file

@ -2362,6 +2362,9 @@
}
}
}
},
"Adds a notch HUD when Caps Lock is enabled, with optional label and tint controls." : {
},
"Adds the AirPlay/route picker button back to the customizable controls palette." : {
@ -4625,6 +4628,9 @@
},
"Caps Lock" : {
},
"Caps Lock Indicator" : {
},
"Center" : {
"extractionState" : "stale",

View file

@ -25,6 +25,7 @@ struct InlineHUD: View {
@Default(.showBluetoothBatteryPercentageText) var showBluetoothBatteryPercentageText
@Default(.showBluetoothDeviceNameMarquee) var showBluetoothDeviceNameMarquee
@Default(.enableMinimalisticUI) var enableMinimalisticUI
@Default(.showCapsLockLabel) var showCapsLockLabel
@ObservedObject var bluetoothManager = BluetoothAudioManager.shared
@State private var displayName: String = ""
@ -32,30 +33,45 @@ struct InlineHUD: View {
var body: some View {
let useCircularIndicator = useCircularBluetoothBatteryIndicator
let hasBatteryLevel = value > 0
let capsLockAccentColor: Color = Defaults[.capsLockIndicatorUseGreenColor] ? .green : .white
let baseInfoWidth: CGFloat = {
guard type == .bluetoothAudio else { return 100 }
if type == .bluetoothAudio {
if showBluetoothDeviceNameMarquee {
return enableMinimalisticUI ? 128 : 140
}
return enableMinimalisticUI ? 64 : 72
}
if type == .capsLock && !showCapsLockLabel {
return enableMinimalisticUI ? 56 : 64
}
return 100
}()
let infoWidth: CGFloat = {
var width = baseInfoWidth + gestureProgress / 2
if !hoverAnimation { width -= 8 }
let minimum: CGFloat = {
guard type == .bluetoothAudio else { return 88 }
if type == .bluetoothAudio {
if showBluetoothDeviceNameMarquee {
return enableMinimalisticUI ? 112 : 120
}
return enableMinimalisticUI ? 56 : 68
}
if type == .capsLock && !showCapsLockLabel {
return enableMinimalisticUI ? 44 : 52
}
return 88
}()
return max(width, minimum)
}()
let baseTrailingWidth: CGFloat = {
guard type == .bluetoothAudio else { return 100 }
if type == .bluetoothAudio {
if !hasBatteryLevel {
return showBluetoothDeviceNameMarquee ? (enableMinimalisticUI ? 104 : 118) : (enableMinimalisticUI ? 74 : 88)
}
@ -65,13 +81,23 @@ struct InlineHUD: View {
}
return showBluetoothBatteryPercentageText ? (enableMinimalisticUI ? 118 : 136) : (enableMinimalisticUI ? 92 : 108)
}
if type == .capsLock {
if showCapsLockLabel {
return enableMinimalisticUI ? 84 : 96
}
return 0
}
return 100
}()
let trailingWidth: CGFloat = {
var width = baseTrailingWidth + gestureProgress / 2
if !hoverAnimation { width -= 8 }
let minimum: CGFloat = {
guard type == .bluetoothAudio else { return 90 }
if type == .bluetoothAudio {
if !hasBatteryLevel {
return showBluetoothDeviceNameMarquee ? (enableMinimalisticUI ? 96 : 110) : (enableMinimalisticUI ? 62 : 88)
}
@ -81,6 +107,13 @@ struct InlineHUD: View {
}
return showBluetoothBatteryPercentageText ? (enableMinimalisticUI ? 104 : 120) : (enableMinimalisticUI ? 72 : 90)
}
if type == .capsLock {
return showCapsLockLabel ? (enableMinimalisticUI ? 68 : 80) : 0
}
return 90
}()
return max(width, minimum)
}()
@ -133,7 +166,7 @@ struct InlineHUD: View {
.symbolRenderingMode(.hierarchical)
.contentTransition(.interpolate)
.frame(width: 20, height: 15, alignment: .center)
.foregroundStyle(Defaults[.capsLockIndicatorUseGreenColor] ? .green : .white)
.foregroundStyle(capsLockAccentColor)
default:
EmptyView()
}
@ -187,8 +220,9 @@ struct InlineHUD: View {
.frame(maxWidth: .infinity, alignment: .trailing)
.contentTransition(.interpolate)
} else if (type == .capsLock) {
if showCapsLockLabel {
Text("Caps Lock")
.foregroundStyle(Defaults[.capsLockIndicatorUseGreenColor] ? .green : .white)
.foregroundStyle(capsLockAccentColor)
.font(.subheadline)
.fontWeight(.medium)
.lineLimit(1)
@ -196,6 +230,7 @@ struct InlineHUD: View {
.multilineTextAlignment(.trailing)
.frame(maxWidth: .infinity, alignment: .trailing)
.contentTransition(.interpolate)
}
} else if (type == .bluetoothAudio) {
if hasBatteryLevel {
let indicatorSpacing: CGFloat = {

View file

@ -1735,11 +1735,6 @@ private struct DevicesSettingsView: View {
Section {
Defaults.Toggle("Show Bluetooth device connections", key: .showBluetoothDeviceConnections)
.settingsHighlight(id: highlightID("Show Bluetooth device connections"))
Defaults.Toggle("Show Caps Lock Indicator", key: .enableCapsLockIndicator)
.settingsHighlight(id: highlightID("Show Caps Lock Indicator"))
Defaults.Toggle("Use green color for Caps Lock text", key: .capsLockIndicatorUseGreenColor)
.disabled(!Defaults[.enableCapsLockIndicator])
.settingsHighlight(id: highlightID("Use green color for Caps Lock text"))
Defaults.Toggle("Use circular battery indicator", key: .useCircularBluetoothBatteryIndicator)
.settingsHighlight(id: highlightID("Use circular battery indicator"))
Defaults.Toggle("Show battery percentage text in HUD", key: .showBluetoothBatteryPercentageText)
@ -2644,6 +2639,23 @@ struct LiveActivitiesSettings: View {
Text("Listens for Focus session changes via distributed notifications")
}
Section {
Defaults.Toggle("Show Caps Lock Indicator", key: .enableCapsLockIndicator)
.settingsHighlight(id: highlightID("Show Caps Lock Indicator"))
Defaults.Toggle("Show Caps Lock label", key: .showCapsLockLabel)
.disabled(!Defaults[.enableCapsLockIndicator])
.settingsHighlight(id: highlightID("Show Caps Lock label"))
Defaults.Toggle("Use green color for Caps Lock text", key: .capsLockIndicatorUseGreenColor)
.disabled(!Defaults[.enableCapsLockIndicator])
.settingsHighlight(id: highlightID("Use green color for Caps Lock text"))
} header: {
Text("Caps Lock Indicator")
} footer: {
Text("Adds a notch HUD when Caps Lock is enabled, with optional label and tint controls.")
}
Section {
Defaults.Toggle("Enable Camera Detection", key: .enableCameraDetection)
.settingsHighlight(id: highlightID("Enable Camera Detection"))

View file

@ -10,6 +10,7 @@ import Foundation
import Combine
import AppKit
import Defaults
import SwiftUI
@MainActor
class CapsLockManager: ObservableObject {
@ -20,6 +21,7 @@ class CapsLockManager: ObservableObject {
private var localEventMonitor: Any?
private var globalEventMonitor: Any?
private let coordinator = DynamicIslandViewCoordinator.shared
private let capsLockAnimation = Animation.spring(response: 0.32, dampingFraction: 0.85)
private init() {
// Get initial state
@ -55,7 +57,9 @@ class CapsLockManager: ObservableObject {
guard newState != isCapsLockActive else { return }
withAnimation(capsLockAnimation) {
isCapsLockActive = newState
}
print("CapsLockManager: Caps Lock \(newState ? "ACTIVATED" : "DEACTIVATED")")

View file

@ -741,6 +741,7 @@ extension Defaults.Keys {
// MARK: Caps Lock Indicator
static let enableCapsLockIndicator = Key<Bool>("enableCapsLockIndicator", default: true)
static let capsLockIndicatorUseGreenColor = Key<Bool>("capsLockIndicatorUseGreenColor", default: false)
static let showCapsLockLabel = Key<Bool>("showCapsLockLabel", default: true)
// MARK: ImageService
static let didClearLegacyURLCacheV1 = Key<Bool>("didClearLegacyURLCacheV1", default: false)