mirror of
https://github.com/FBukovina/Atoll.git
synced 2026-10-27 15:14:33 +00:00
Fix: Caps Lock View
This commit is contained in:
parent
5822d9a232
commit
168dc27af5
6 changed files with 100 additions and 38 deletions
|
|
@ -485,10 +485,14 @@ struct ContentView: View {
|
||||||
.frame(height: vm.effectiveClosedNotchHeight + (isHovering ? 8 : 0), alignment: .center)
|
.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) {
|
} 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)
|
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 {
|
} 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)
|
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 {
|
} else if (!coordinator.expandingView.show || coordinator.expandingView.type == .music) && vm.notchState == .closed && (musicManager.isPlaying || !musicManager.isPlayerIdle) && coordinator.musicLiveActivityEnabled && !vm.hideOnClosed && !lockScreenManager.isLocked {
|
||||||
MusicLiveActivity()
|
MusicLiveActivity()
|
||||||
} else if (!coordinator.expandingView.show || coordinator.expandingView.type == .timer) && vm.notchState == .closed && timerManager.isTimerActive && coordinator.timerLiveActivityEnabled && !vm.hideOnClosed {
|
} else if (!coordinator.expandingView.show || coordinator.expandingView.type == .timer) && vm.notchState == .closed && timerManager.isTimerActive && coordinator.timerLiveActivityEnabled && !vm.hideOnClosed {
|
||||||
|
|
|
||||||
|
|
@ -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." : {
|
"Adds the AirPlay/route picker button back to the customizable controls palette." : {
|
||||||
|
|
||||||
|
|
@ -4625,6 +4628,9 @@
|
||||||
},
|
},
|
||||||
"Caps Lock" : {
|
"Caps Lock" : {
|
||||||
|
|
||||||
|
},
|
||||||
|
"Caps Lock Indicator" : {
|
||||||
|
|
||||||
},
|
},
|
||||||
"Center" : {
|
"Center" : {
|
||||||
"extractionState" : "stale",
|
"extractionState" : "stale",
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ struct InlineHUD: View {
|
||||||
@Default(.showBluetoothBatteryPercentageText) var showBluetoothBatteryPercentageText
|
@Default(.showBluetoothBatteryPercentageText) var showBluetoothBatteryPercentageText
|
||||||
@Default(.showBluetoothDeviceNameMarquee) var showBluetoothDeviceNameMarquee
|
@Default(.showBluetoothDeviceNameMarquee) var showBluetoothDeviceNameMarquee
|
||||||
@Default(.enableMinimalisticUI) var enableMinimalisticUI
|
@Default(.enableMinimalisticUI) var enableMinimalisticUI
|
||||||
|
@Default(.showCapsLockLabel) var showCapsLockLabel
|
||||||
@ObservedObject var bluetoothManager = BluetoothAudioManager.shared
|
@ObservedObject var bluetoothManager = BluetoothAudioManager.shared
|
||||||
|
|
||||||
@State private var displayName: String = ""
|
@State private var displayName: String = ""
|
||||||
|
|
@ -32,55 +33,87 @@ struct InlineHUD: View {
|
||||||
var body: some View {
|
var body: some View {
|
||||||
let useCircularIndicator = useCircularBluetoothBatteryIndicator
|
let useCircularIndicator = useCircularBluetoothBatteryIndicator
|
||||||
let hasBatteryLevel = value > 0
|
let hasBatteryLevel = value > 0
|
||||||
|
let capsLockAccentColor: Color = Defaults[.capsLockIndicatorUseGreenColor] ? .green : .white
|
||||||
|
|
||||||
let baseInfoWidth: CGFloat = {
|
let baseInfoWidth: CGFloat = {
|
||||||
guard type == .bluetoothAudio else { return 100 }
|
if type == .bluetoothAudio {
|
||||||
if showBluetoothDeviceNameMarquee {
|
if showBluetoothDeviceNameMarquee {
|
||||||
return enableMinimalisticUI ? 128 : 140
|
return enableMinimalisticUI ? 128 : 140
|
||||||
|
}
|
||||||
|
return enableMinimalisticUI ? 64 : 72
|
||||||
}
|
}
|
||||||
return enableMinimalisticUI ? 64 : 72
|
|
||||||
|
if type == .capsLock && !showCapsLockLabel {
|
||||||
|
return enableMinimalisticUI ? 56 : 64
|
||||||
|
}
|
||||||
|
|
||||||
|
return 100
|
||||||
}()
|
}()
|
||||||
|
|
||||||
let infoWidth: CGFloat = {
|
let infoWidth: CGFloat = {
|
||||||
var width = baseInfoWidth + gestureProgress / 2
|
var width = baseInfoWidth + gestureProgress / 2
|
||||||
if !hoverAnimation { width -= 8 }
|
if !hoverAnimation { width -= 8 }
|
||||||
let minimum: CGFloat = {
|
let minimum: CGFloat = {
|
||||||
guard type == .bluetoothAudio else { return 88 }
|
if type == .bluetoothAudio {
|
||||||
if showBluetoothDeviceNameMarquee {
|
if showBluetoothDeviceNameMarquee {
|
||||||
return enableMinimalisticUI ? 112 : 120
|
return enableMinimalisticUI ? 112 : 120
|
||||||
|
}
|
||||||
|
return enableMinimalisticUI ? 56 : 68
|
||||||
}
|
}
|
||||||
return enableMinimalisticUI ? 56 : 68
|
|
||||||
|
if type == .capsLock && !showCapsLockLabel {
|
||||||
|
return enableMinimalisticUI ? 44 : 52
|
||||||
|
}
|
||||||
|
|
||||||
|
return 88
|
||||||
}()
|
}()
|
||||||
return max(width, minimum)
|
return max(width, minimum)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
let baseTrailingWidth: CGFloat = {
|
let baseTrailingWidth: CGFloat = {
|
||||||
guard type == .bluetoothAudio else { return 100 }
|
if type == .bluetoothAudio {
|
||||||
if !hasBatteryLevel {
|
if !hasBatteryLevel {
|
||||||
return showBluetoothDeviceNameMarquee ? (enableMinimalisticUI ? 104 : 118) : (enableMinimalisticUI ? 74 : 88)
|
return showBluetoothDeviceNameMarquee ? (enableMinimalisticUI ? 104 : 118) : (enableMinimalisticUI ? 74 : 88)
|
||||||
|
}
|
||||||
|
|
||||||
|
if useCircularIndicator {
|
||||||
|
return showBluetoothBatteryPercentageText ? (enableMinimalisticUI ? 108 : 120) : (enableMinimalisticUI ? 72 : 84)
|
||||||
|
}
|
||||||
|
|
||||||
|
return showBluetoothBatteryPercentageText ? (enableMinimalisticUI ? 118 : 136) : (enableMinimalisticUI ? 92 : 108)
|
||||||
}
|
}
|
||||||
|
|
||||||
if useCircularIndicator {
|
if type == .capsLock {
|
||||||
return showBluetoothBatteryPercentageText ? (enableMinimalisticUI ? 108 : 120) : (enableMinimalisticUI ? 72 : 84)
|
if showCapsLockLabel {
|
||||||
|
return enableMinimalisticUI ? 84 : 96
|
||||||
|
}
|
||||||
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
return showBluetoothBatteryPercentageText ? (enableMinimalisticUI ? 118 : 136) : (enableMinimalisticUI ? 92 : 108)
|
return 100
|
||||||
}()
|
}()
|
||||||
|
|
||||||
let trailingWidth: CGFloat = {
|
let trailingWidth: CGFloat = {
|
||||||
var width = baseTrailingWidth + gestureProgress / 2
|
var width = baseTrailingWidth + gestureProgress / 2
|
||||||
if !hoverAnimation { width -= 8 }
|
if !hoverAnimation { width -= 8 }
|
||||||
let minimum: CGFloat = {
|
let minimum: CGFloat = {
|
||||||
guard type == .bluetoothAudio else { return 90 }
|
if type == .bluetoothAudio {
|
||||||
if !hasBatteryLevel {
|
if !hasBatteryLevel {
|
||||||
return showBluetoothDeviceNameMarquee ? (enableMinimalisticUI ? 96 : 110) : (enableMinimalisticUI ? 62 : 88)
|
return showBluetoothDeviceNameMarquee ? (enableMinimalisticUI ? 96 : 110) : (enableMinimalisticUI ? 62 : 88)
|
||||||
|
}
|
||||||
|
|
||||||
|
if useCircularIndicator {
|
||||||
|
return showBluetoothBatteryPercentageText ? (enableMinimalisticUI ? 92 : 110) : (enableMinimalisticUI ? 56 : 72)
|
||||||
|
}
|
||||||
|
|
||||||
|
return showBluetoothBatteryPercentageText ? (enableMinimalisticUI ? 104 : 120) : (enableMinimalisticUI ? 72 : 90)
|
||||||
}
|
}
|
||||||
|
|
||||||
if useCircularIndicator {
|
if type == .capsLock {
|
||||||
return showBluetoothBatteryPercentageText ? (enableMinimalisticUI ? 92 : 110) : (enableMinimalisticUI ? 56 : 72)
|
return showCapsLockLabel ? (enableMinimalisticUI ? 68 : 80) : 0
|
||||||
}
|
}
|
||||||
|
|
||||||
return showBluetoothBatteryPercentageText ? (enableMinimalisticUI ? 104 : 120) : (enableMinimalisticUI ? 72 : 90)
|
return 90
|
||||||
}()
|
}()
|
||||||
return max(width, minimum)
|
return max(width, minimum)
|
||||||
}()
|
}()
|
||||||
|
|
@ -133,7 +166,7 @@ struct InlineHUD: View {
|
||||||
.symbolRenderingMode(.hierarchical)
|
.symbolRenderingMode(.hierarchical)
|
||||||
.contentTransition(.interpolate)
|
.contentTransition(.interpolate)
|
||||||
.frame(width: 20, height: 15, alignment: .center)
|
.frame(width: 20, height: 15, alignment: .center)
|
||||||
.foregroundStyle(Defaults[.capsLockIndicatorUseGreenColor] ? .green : .white)
|
.foregroundStyle(capsLockAccentColor)
|
||||||
default:
|
default:
|
||||||
EmptyView()
|
EmptyView()
|
||||||
}
|
}
|
||||||
|
|
@ -187,15 +220,17 @@ struct InlineHUD: View {
|
||||||
.frame(maxWidth: .infinity, alignment: .trailing)
|
.frame(maxWidth: .infinity, alignment: .trailing)
|
||||||
.contentTransition(.interpolate)
|
.contentTransition(.interpolate)
|
||||||
} else if (type == .capsLock) {
|
} else if (type == .capsLock) {
|
||||||
Text("Caps Lock")
|
if showCapsLockLabel {
|
||||||
.foregroundStyle(Defaults[.capsLockIndicatorUseGreenColor] ? .green : .white)
|
Text("Caps Lock")
|
||||||
.font(.subheadline)
|
.foregroundStyle(capsLockAccentColor)
|
||||||
.fontWeight(.medium)
|
.font(.subheadline)
|
||||||
.lineLimit(1)
|
.fontWeight(.medium)
|
||||||
.allowsTightening(true)
|
.lineLimit(1)
|
||||||
.multilineTextAlignment(.trailing)
|
.allowsTightening(true)
|
||||||
.frame(maxWidth: .infinity, alignment: .trailing)
|
.multilineTextAlignment(.trailing)
|
||||||
.contentTransition(.interpolate)
|
.frame(maxWidth: .infinity, alignment: .trailing)
|
||||||
|
.contentTransition(.interpolate)
|
||||||
|
}
|
||||||
} else if (type == .bluetoothAudio) {
|
} else if (type == .bluetoothAudio) {
|
||||||
if hasBatteryLevel {
|
if hasBatteryLevel {
|
||||||
let indicatorSpacing: CGFloat = {
|
let indicatorSpacing: CGFloat = {
|
||||||
|
|
|
||||||
|
|
@ -1735,11 +1735,6 @@ private struct DevicesSettingsView: View {
|
||||||
Section {
|
Section {
|
||||||
Defaults.Toggle("Show Bluetooth device connections", key: .showBluetoothDeviceConnections)
|
Defaults.Toggle("Show Bluetooth device connections", key: .showBluetoothDeviceConnections)
|
||||||
.settingsHighlight(id: highlightID("Show Bluetooth device connections"))
|
.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)
|
Defaults.Toggle("Use circular battery indicator", key: .useCircularBluetoothBatteryIndicator)
|
||||||
.settingsHighlight(id: highlightID("Use circular battery indicator"))
|
.settingsHighlight(id: highlightID("Use circular battery indicator"))
|
||||||
Defaults.Toggle("Show battery percentage text in HUD", key: .showBluetoothBatteryPercentageText)
|
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")
|
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 {
|
Section {
|
||||||
Defaults.Toggle("Enable Camera Detection", key: .enableCameraDetection)
|
Defaults.Toggle("Enable Camera Detection", key: .enableCameraDetection)
|
||||||
.settingsHighlight(id: highlightID("Enable Camera Detection"))
|
.settingsHighlight(id: highlightID("Enable Camera Detection"))
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import Foundation
|
||||||
import Combine
|
import Combine
|
||||||
import AppKit
|
import AppKit
|
||||||
import Defaults
|
import Defaults
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
class CapsLockManager: ObservableObject {
|
class CapsLockManager: ObservableObject {
|
||||||
|
|
@ -20,6 +21,7 @@ class CapsLockManager: ObservableObject {
|
||||||
private var localEventMonitor: Any?
|
private var localEventMonitor: Any?
|
||||||
private var globalEventMonitor: Any?
|
private var globalEventMonitor: Any?
|
||||||
private let coordinator = DynamicIslandViewCoordinator.shared
|
private let coordinator = DynamicIslandViewCoordinator.shared
|
||||||
|
private let capsLockAnimation = Animation.spring(response: 0.32, dampingFraction: 0.85)
|
||||||
|
|
||||||
private init() {
|
private init() {
|
||||||
// Get initial state
|
// Get initial state
|
||||||
|
|
@ -55,7 +57,9 @@ class CapsLockManager: ObservableObject {
|
||||||
|
|
||||||
guard newState != isCapsLockActive else { return }
|
guard newState != isCapsLockActive else { return }
|
||||||
|
|
||||||
isCapsLockActive = newState
|
withAnimation(capsLockAnimation) {
|
||||||
|
isCapsLockActive = newState
|
||||||
|
}
|
||||||
|
|
||||||
print("CapsLockManager: Caps Lock \(newState ? "ACTIVATED" : "DEACTIVATED")")
|
print("CapsLockManager: Caps Lock \(newState ? "ACTIVATED" : "DEACTIVATED")")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -741,6 +741,7 @@ extension Defaults.Keys {
|
||||||
// MARK: Caps Lock Indicator
|
// MARK: Caps Lock Indicator
|
||||||
static let enableCapsLockIndicator = Key<Bool>("enableCapsLockIndicator", default: true)
|
static let enableCapsLockIndicator = Key<Bool>("enableCapsLockIndicator", default: true)
|
||||||
static let capsLockIndicatorUseGreenColor = Key<Bool>("capsLockIndicatorUseGreenColor", default: false)
|
static let capsLockIndicatorUseGreenColor = Key<Bool>("capsLockIndicatorUseGreenColor", default: false)
|
||||||
|
static let showCapsLockLabel = Key<Bool>("showCapsLockLabel", default: true)
|
||||||
|
|
||||||
// MARK: ImageService
|
// MARK: ImageService
|
||||||
static let didClearLegacyURLCacheV1 = Key<Bool>("didClearLegacyURLCacheV1", default: false)
|
static let didClearLegacyURLCacheV1 = Key<Bool>("didClearLegacyURLCacheV1", default: false)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue