Skip to content

feat: remember the selected profile across launches - #45

Open
bakirgdev-symphony wants to merge 1 commit into
ProducerGuy:mainfrom
bakirgdev-symphony:feat/persist-profile
Open

bakirgdev-symphony wants to merge 1 commit into
ProducerGuy:mainfrom
bakirgdev-symphony:feat/persist-profile

Conversation

@bakirgdev-symphony

Copy link
Copy Markdown

What this fixes

AppState.activeProfile is initialised to .silent and never restored. Every app restart, update, crash or logout silently hands the machine back to Apple's fan curve.

There is no signal that it happened. The daemon keeps running, the menu bar icon stays where it was, and the only symptom is that the machine runs hotter than it did yesterday until someone notices and re-picks a profile. On a machine that heats quickly this is the difference between the curve engaging on schedule and the 95°C safety override being the first thing that spins the fans.

The current UserDefaults surface persists useFahrenheit and the update-check bookkeeping, but not the one setting the whole app exists to express.

Changes

Sources/ThermalForgeApp/AppState.swift only, no new dependencies, no protocol or daemon changes.

  • New activeProfileKey default. restoredProfile() resolves the stored id against FanProfile.loadAll() at launch.
  • The restore runs before startMonitoring(). That ordering matters: startMonitoring() passes activeProfile into the ThermalMonitor it constructs, so restoring after that point would update the menu but leave the monitor on Silent.
  • Persisted from the three places the user expresses intent — selectProfile, setSmart, resetAuto — rather than from a didSet on activeProfile. The monitor's onUpdate writes that property every 500ms and its in-flight value can still carry the previous profile for one tick after a switchProfile, so a didSet would briefly persist the profile the user just moved away from.
  • smart is not in loadAll() and is resolved explicitly. A custom profile deleted since it was chosen falls back to .silent, so the menu can never show a profile the monitor is not actually running.

Interaction with existing behaviour

  • An active CLI hold is unaffected. adoptDaemonStateOnLaunch still reflects it and onFanCommand still bails while externalHold != nil; the restored profile simply does not act until the hold clears.
  • resetAuto (the Default button) persists .silent, so "give me back Apple's curve" is itself remembered rather than being undone by the next launch.
  • First launch on an existing install reads no key and returns .silent, which is today's behaviour.

Verification

  • swift build -c release clean (Swift 6.3.3, Xcode 26.6, arm64).
  • swift test: 48 tests in 8 suites, all pass.
  • Running on an M5 Pro (Mac17,8), macOS 26.6.2: profile survives quit/relaunch and reboot, and the monitor resumes on the restored curve rather than on Silent.

Independent of #44 — separate branch off main, no overlapping hunks.

activeProfile is initialised to .silent and never restored, so every
restart, update, crash or logout silently hands the machine back to
Apple's curve. Nothing tells the user: the daemon keeps running, the menu
bar icon stays put, and the only symptom is that the machine runs hotter
than it did yesterday until someone notices and re-picks a profile.

A fan profile is a standing preference. Persist the chosen id and resolve
it at launch, before startMonitoring() constructs the ThermalMonitor —
restoring after that point would update the menu but not the monitor.

Persisted from the three places the user expresses intent (selectProfile,
setSmart, resetAuto) rather than from a didSet on activeProfile: the
monitor's onUpdate writes that property every 500ms and its in-flight
value can still carry the previous profile for one tick after a switch.

Smart is not in loadAll() and a custom profile may have been deleted since
it was chosen, so restore falls back to Apple's default rather than
leaving the menu showing a profile the monitor is not running.
@bakirgdev-symphony

Copy link
Copy Markdown
Author

hi. read #44

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant