feat: add icon animation setting

This commit is contained in:
Peter Steinberger
2025-12-07 04:38:18 +01:00
parent 6c3d3b98b8
commit 060f80c239
4 changed files with 38 additions and 1 deletions

View File

@@ -40,6 +40,10 @@ final class AppState: ObservableObject {
}
}
@Published var iconAnimationsEnabled: Bool {
didSet { UserDefaults.standard.set(self.iconAnimationsEnabled, forKey: iconAnimationsEnabledKey) }
}
@Published var showDockIcon: Bool {
didSet {
UserDefaults.standard.set(self.showDockIcon, forKey: showDockIconKey)
@@ -90,6 +94,12 @@ final class AppState: ObservableObject {
self.swabbleEnabled = voiceWakeSupported ? savedVoiceWake : false
self.swabbleTriggerWords = UserDefaults.standard
.stringArray(forKey: swabbleTriggersKey) ?? defaultVoiceWakeTriggers
if let storedIconAnimations = UserDefaults.standard.object(forKey: iconAnimationsEnabledKey) as? Bool {
self.iconAnimationsEnabled = storedIconAnimations
} else {
self.iconAnimationsEnabled = true
UserDefaults.standard.set(true, forKey: iconAnimationsEnabledKey)
}
self.showDockIcon = UserDefaults.standard.bool(forKey: showDockIconKey)
self.voiceWakeMicID = UserDefaults.standard.string(forKey: voiceWakeMicKey) ?? ""
self.voiceWakeLocaleID = UserDefaults.standard.string(forKey: voiceWakeLocaleKey) ?? Locale.current.identifier

View File

@@ -5,6 +5,7 @@ let launchdLabel = "com.steipete.clawdis"
let onboardingVersionKey = "clawdis.onboardingVersion"
let currentOnboardingVersion = 2
let pauseDefaultsKey = "clawdis.pauseEnabled"
let iconAnimationsEnabledKey = "clawdis.iconAnimationsEnabled"
let swabbleEnabledKey = "clawdis.swabbleEnabled"
let swabbleTriggersKey = "clawdis.swabbleTriggers"
let showDockIconKey = "clawdis.showDockIcon"

View File

@@ -33,6 +33,11 @@ struct GeneralSettings: View {
subtitle: "Keep Clawdis visible in the Dock instead of menu-bar-only mode.",
binding: self.$state.showDockIcon)
SettingsToggleRow(
title: "Play menu bar icon animations",
subtitle: "Enable idle blinks and wiggles on the status icon.",
binding: self.$state.iconAnimationsEnabled)
SettingsToggleRow(
title: "Enable debug tools",
subtitle: "Show the Debug tab with development utilities.",

View File

@@ -25,7 +25,8 @@ struct ClawdisApp: App {
isPaused: self.state.isPaused,
isWorking: self.state.isWorking,
earBoostActive: self.state.earBoostActive,
relayStatus: self.relayManager.status)
relayStatus: self.relayManager.status,
animationsEnabled: self.state.iconAnimationsEnabled)
}
.menuBarExtraStyle(.menu)
.menuBarExtraAccess(isPresented: self.$isMenuPresented) { item in
@@ -137,6 +138,7 @@ private struct CritterStatusLabel: View {
var isWorking: Bool
var earBoostActive: Bool
var relayStatus: RelayProcessManager.Status
var animationsEnabled: Bool
@State private var blinkAmount: CGFloat = 0
@State private var nextBlink = Date().addingTimeInterval(Double.random(in: 3.5...8.5))
@@ -165,6 +167,11 @@ private struct CritterStatusLabel: View {
.rotationEffect(.degrees(self.wiggleAngle), anchor: .center)
.offset(x: self.wiggleOffset)
.onReceive(self.ticker) { now in
guard self.animationsEnabled else {
self.resetMotion()
return
}
if now >= self.nextBlink {
self.blink()
self.nextBlink = now.addingTimeInterval(Double.random(in: 3.5...8.5))
@@ -190,6 +197,13 @@ private struct CritterStatusLabel: View {
}
}
.onChange(of: self.isPaused) { _, _ in self.resetMotion() }
.onChange(of: self.animationsEnabled) { _, enabled in
if enabled {
self.scheduleRandomTimers(from: Date())
} else {
self.resetMotion()
}
}
}
}
@@ -266,6 +280,13 @@ private struct CritterStatusLabel: View {
}
}
private func scheduleRandomTimers(from date: Date) {
self.nextBlink = date.addingTimeInterval(Double.random(in: 3.5...8.5))
self.nextWiggle = date.addingTimeInterval(Double.random(in: 6.5...14))
self.nextLegWiggle = date.addingTimeInterval(Double.random(in: 5.0...11.0))
self.nextEarWiggle = date.addingTimeInterval(Double.random(in: 7.0...14.0))
}
private var relayNeedsAttention: Bool {
switch self.relayStatus {
case .failed, .stopped: