Files
Allofit/sources/ui/AppActivity.swift
Bitsy 547753cc4d Status bar stats, background throttling, Performance settings, drag fix
- Status bar: last search time, memory footprint, CPU use (highlighted when
  busy) and role, with a tooltip for peak memory, threads, index age, cache
  size and roots. Sampled every 2 s, redraws only the status bar; match count
  and search time live in a separate object so the table isn't re-rendered.
- Background throttling: file changes are collected longer and open results
  refresh less often when Allofit isn't focused or no window is visible;
  sampling pauses when hidden. Showing a window applies pending changes at
  once.
- Settings > Performance: the update delays (focused / another app focused /
  no window) and result refresh intervals, with an estimate of how soon a
  changed file appears and Restore Defaults. Defaults 2 s / 15 s / 1 min and
  1 s / 5 s.
- Drag rows as file URLs (like Finder) instead of a plain link, so browsers
  upload the file instead of navigating to it.
- Canonicalize roots with realpath: roots under /tmp, /var or /etc never
  matched their own entries because Foundation strips /private.
2026-10-02 10:20:45 +02:00

84 lines
2.4 KiB
Swift

import AppKit
import Combine
// AppActivity tracks how visible Allofit currently is, so background work
// can slow down when nobody is looking:
// - foreground: the app is frontmost and one of its windows is on screen
// - background: a window is on screen but another app has focus
// - hidden: no window is on screen (closed, minimized, fully covered,
// or the app is hidden)
// Windows report their own visibility through WindowVisibilityReporter.
@MainActor
final class AppActivity: ObservableObject {
// shared tracker for the whole app
static let shared = AppActivity()
// how visible the app is, from least to most
enum Level: Int, Comparable {
case hidden = 0
case background = 1
case foreground = 2
// ordering by visibility
static func < (inLhs: Level, inRhs: Level) -> Bool {
return inLhs.rawValue < inRhs.rawValue
}
}
// current visibility level
@Published private(set) var level: Level = .foreground
// windows (by reporter identity) currently on screen
private var visibleWindows = Set<ObjectIdentifier>()
// true while Allofit is the frontmost app
private var isAppActive = true
// app activation observers
private var cancellables: Set<AnyCancellable> = []
// starts following app activation / hiding
private init() {
isAppActive = NSApplication.shared.isActive
let vCenter = NotificationCenter.default
for vName in [NSApplication.didBecomeActiveNotification,
NSApplication.didResignActiveNotification,
NSApplication.didHideNotification,
NSApplication.didUnhideNotification] {
vCenter.publisher(for: vName)
.sink { [weak self] _ in
MainActor.assumeIsolated {
guard let vSelf = self else { return }
vSelf.isAppActive = NSApplication.shared.isActive && !NSApplication.shared.isHidden
vSelf.recompute()
}
}
.store(in: &cancellables)
}
}
// records whether the window identified by inId is on screen
func setWindow(_ inId: ObjectIdentifier, visible inVisible: Bool) {
if inVisible {
visibleWindows.insert(inId)
} else {
visibleWindows.remove(inId)
}
recompute()
}
// derives the level from the window set and the app's active state
private func recompute() {
let vLevel: Level
if visibleWindows.isEmpty || NSApplication.shared.isHidden {
vLevel = .hidden
} else if isAppActive {
vLevel = .foreground
} else {
vLevel = .background
}
if level != vLevel {
level = vLevel
}
}
}