HotFix: Remove Unnecessary Mach service for Stats

This commit is contained in:
Hariharan Mudaliar 2026-03-20 20:24:08 +05:30
commit 28320e4cb8
No known key found for this signature in database
GPG key ID: 025583EB0BE5640E
11 changed files with 58 additions and 161 deletions

View file

@ -9907,9 +9907,13 @@
}
}
}
},
"Enable \"Idle Animation\" to customize animations" : {
},
"Enable \"Show cool face animation while inactivity\" to customize animations" : {
"comment" : "A message displayed below the section header in the IdleAnimationsSettingsSection, explaining that users can customize animations by enabling this feature.",
"extractionState" : "stale",
"isCommentAutoGenerated" : true,
"localizations" : {
"pt-BR" : {

View file

@ -1,98 +0,0 @@
/*
* Atoll (DynamicIsland)
* Copyright (C) 2024-2026 Atoll Contributors
*
* Originally from boring.notch project
* Modified and adapted for Atoll (DynamicIsland)
* See NOTICE for details.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import SwiftUI
struct MinimalFaceFeatures: View {
@State private var isBlinking = false
@State var height:CGFloat = 20;
@State var width:CGFloat = 30;
var body: some View {
VStack(spacing: 4) { // Adjusted spacing to fit within 30x30
// Eyes
HStack(spacing: 4) { // Adjusted spacing to fit within 30x30
Eye(isBlinking: $isBlinking)
Eye(isBlinking: $isBlinking)
}
// Nose and mouth combined
VStack(spacing: 2) { // Adjusted spacing to fit within 30x30
// Nose
RoundedRectangle(cornerRadius: 2)
.fill(Color.white)
.frame(width: 3, height: 4)
// Mouth (happy)
GeometryReader { geometry in
Path { path in
let width = geometry.size.width
let height = geometry.size.height
path.move(to: CGPoint(x: 0, y: height / 2))
path.addQuadCurve(to: CGPoint(x: width, y: height / 2), control: CGPoint(x: width / 2, y: height))
}
.stroke(Color.white, lineWidth: 2)
}
.frame(width: 14, height: 10)
}
}
.frame(width: self.width, height: self.height) // Maximum size of face
.onAppear {
startBlinking()
}
}
func startBlinking() {
Timer.scheduledTimer(withTimeInterval: 3, repeats: true) { _ in
withAnimation(.spring(duration: 0.2)) {
isBlinking = true
}
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
withAnimation(.spring(duration: 0.2)) {
isBlinking = false
}
}
}
}
}
struct Eye: View {
@Binding var isBlinking: Bool
var body: some View {
RoundedRectangle(cornerRadius: 10)
.fill(Color.white)
.frame(width: 4, height: isBlinking ? 1 : 4)
.frame(maxWidth: 15, maxHeight: 15) // Adjusted max size
.animation(.easeInOut(duration: 0.1), value: isBlinking)
}
}
struct MinimalFaceFeatures_Previews: PreviewProvider {
static var previews: some View {
ZStack {
Color.black
MinimalFaceFeatures()
}
.previewLayout(.fixed(width: 60, height: 60)) // Adjusted preview size for better visibility
}
}

View file

@ -28,8 +28,10 @@ struct EmptyStateView: View {
var body: some View {
HStack {
MinimalFaceFeatures(
height: 70, width: 80)
Image(systemName: "music.note")
.font(.system(size: 24))
.foregroundColor(.gray)
.frame(width: 80, height: 70)
Text(message)
.font(.system(size:14))
.foregroundColor(.gray)

View file

@ -31,8 +31,8 @@ struct IdleAnimationView: View {
AnimationContentView(animation: animation)
.id("\(animation.id)-\(overrides[animation.id.uuidString]?.hashValue ?? 0)") // Force recreation when override changes
} else {
// Fallback to original face if nothing selected
MinimalFaceFeatures(height: 20, width: 30)
// No animation selected
EmptyView()
}
}
}
@ -85,20 +85,6 @@ private struct AnimationContentView: View {
.padding(.bottom, config.paddingBottom)
.frame(width: config.expandWithAnimation ? nil : 30, height: 20)
.clipped()
case .builtInFace:
// Apply transforms to built-in face too!
MinimalFaceFeatures(height: 20, width: 30)
.frame(
width: config.cropWidth * config.scale,
height: config.cropHeight * config.scale
)
.offset(x: config.offsetX, y: config.offsetY)
.rotationEffect(.degrees(config.rotation))
.opacity(config.opacity)
.padding(.bottom, config.paddingBottom)
.frame(width: config.expandWithAnimation ? nil : 30, height: 20)
.clipped()
}
}
}

View file

@ -170,16 +170,11 @@ struct AnimationEditorView: View {
.frame(width: 30 * previewScale, height: 20 * previewScale)
Group {
if let existing = existingAnimation, case .builtInFace = existing.source {
MinimalFaceFeatures(height: 20, width: 30)
.scaleEffect(previewScale)
} else {
LottieView(state: LUStateData(
type: .loadedFrom(sourceURL),
speed: speed,
loopMode: loopMode.lottieLoopMode
))
}
LottieView(state: LUStateData(
type: .loadedFrom(sourceURL),
speed: speed,
loopMode: loopMode.lottieLoopMode
))
}
.frame(width: cropWidth * scale * previewScale, height: cropHeight * scale * previewScale)
.offset(x: offsetX * previewScale, y: offsetY * previewScale)

View file

@ -87,12 +87,6 @@ struct IdleAnimationsSettingsSection: View {
print("🔧 [Edit] Lottie URL: \(url)")
editorSourceURL = url
editorIsRemote = true
case .builtInFace:
print("🔧 [Edit] Built-in face - using dummy URL")
// Use a dummy URL for built-in face (editor only needs URL for preview)
editorSourceURL = URL(string: "builtin://face")!
editorIsRemote = false
}
// Show editor with slight delay to ensure state is set
@ -118,7 +112,7 @@ struct IdleAnimationsSettingsSection: View {
}
.frame(height: 140)
} else {
Text("Enable \"Show cool face animation while inactivity\" to customize animations")
Text("Enable \"Idle Animation\" to customize animations")
.font(.caption)
.foregroundStyle(.secondary)
.padding(.vertical, 8)
@ -388,10 +382,6 @@ struct AnimationPreview: View {
loopMode: .loop
))
.frame(width: 60, height: 40)
case .builtInFace:
MinimalFaceFeatures(height: 40, width: 60)
.scaleEffect(2.0) // Scale up the face for preview
}
}
}

View file

@ -807,7 +807,7 @@ struct SettingsView: View {
SettingsSearchEntry(tab: .appearance, title: "Slider color", keywords: ["slider", "accent"], highlightID: SettingsTab.appearance.highlightID(for: "Slider color")),
SettingsSearchEntry(tab: .appearance, title: "Enable Dynamic mirror", keywords: ["mirror", "reflection"], highlightID: SettingsTab.appearance.highlightID(for: "Enable Dynamic mirror")),
SettingsSearchEntry(tab: .appearance, title: "Mirror shape", keywords: ["mirror shape", "circle", "rectangle"], highlightID: SettingsTab.appearance.highlightID(for: "Mirror shape")),
SettingsSearchEntry(tab: .appearance, title: "Show cool face animation while inactivity", keywords: ["face animation", "idle"], highlightID: SettingsTab.appearance.highlightID(for: "Show cool face animation while inactivity")),
SettingsSearchEntry(tab: .appearance, title: "Idle Animation", keywords: ["face animation", "idle", "cool face"], highlightID: SettingsTab.appearance.highlightID(for: "Idle Animation")),
SettingsSearchEntry(tab: .appearance, title: "App icon", keywords: ["app icon", "custom icon"], highlightID: SettingsTab.appearance.highlightID(for: "App icon")),
// Lock Screen
@ -3951,8 +3951,8 @@ struct Appearance: View {
.tag(MirrorShapeEnum.rectangle)
}
.settingsHighlight(id: highlightID("Mirror shape"))
Defaults.Toggle("Show cool face animation while inactivity", key: .showNotHumanFace)
.settingsHighlight(id: highlightID("Show cool face animation while inactivity"))
Defaults.Toggle("Idle Animation", key: .showNotHumanFace)
.settingsHighlight(id: highlightID("Idle Animation"))
} header: {
HStack {
Text("Additional features")

View file

@ -39,19 +39,10 @@ class IdleAnimationManager {
// MARK: - Initialization
/// Load bundled animations from the LottieAnimations folder and built-in face
/// Load bundled animations from the LottieAnimations folder
func initializeDefaultAnimations() {
var animations: [CustomIdleAnimation] = []
// Add built-in face as first option
let builtInFace = CustomIdleAnimation(
name: "Classic Face",
source: .builtInFace,
speed: 1.0,
isBuiltIn: true
)
animations.append(builtInFace)
// Load bundled Lottie files
if let bundledAnimations = loadBundledAnimations() {
animations.append(contentsOf: bundledAnimations)
@ -60,14 +51,21 @@ class IdleAnimationManager {
// Get existing animations
var existing = Defaults[.customIdleAnimations]
// Remove any legacy builtInFace entries that may be stored from older versions
existing.removeAll { animation in
if case .lottieFile(let url) = animation.source, url.absoluteString == "builtin://face" {
return true
}
return false
}
if existing.isEmpty {
// First launch - set everything
Defaults[.customIdleAnimations] = animations
Defaults[.selectedIdleAnimation] = builtInFace
Defaults[.selectedIdleAnimation] = animations.first
print("✅ [IdleAnimationManager] First launch: Initialized with \(animations.count) animations")
} else {
// Subsequent launch - ensure all bundled animations are present
let existingIDs = Set(existing.map { $0.id })
let existingNames = Set(existing.filter { $0.isBuiltIn }.map { $0.name })
// Add any missing bundled animations
@ -79,7 +77,23 @@ class IdleAnimationManager {
}
Defaults[.customIdleAnimations] = existing
print("✅ [IdleAnimationManager] Subsequent launch: \(existing.count) total animations (\(animations.count - 1) bundled + built-in face)")
// If current selection was the old built-in face (no longer valid), select first available
if let selected = Defaults[.selectedIdleAnimation] {
let isValid: Bool
switch selected.source {
case .lottieFile(let url):
isValid = url.absoluteString != "builtin://face"
case .lottieURL:
isValid = true
}
if !isValid {
Defaults[.selectedIdleAnimation] = existing.first
print("🔄 [IdleAnimationManager] Migrated selection from legacy face to: \(existing.first?.name ?? "nil")")
}
}
print("✅ [IdleAnimationManager] Subsequent launch: \(existing.count) total animations")
}
}

View file

@ -414,14 +414,20 @@ class StatsManager: ObservableObject {
private var delayedStopTimer: Timer?
private var delayedStartTimer: Timer?
private let maxHistoryPoints = 30
/// Cached host port to avoid leaking Mach send rights.
/// Every call to `mach_host_self()` acquires a new send right that must be
/// explicitly deallocated; caching it once prevents port exhaustion over time.
private let hostPort: mach_port_t = mach_host_self()
private let totalPhysicalMemory: UInt64 = {
var stats = host_basic_info()
var count = mach_msg_type_number_t(MemoryLayout<host_basic_info_data_t>.size / MemoryLayout<integer_t>.size)
let initHostPort = mach_host_self()
let result = withUnsafeMutablePointer(to: &stats) {
$0.withMemoryRebound(to: integer_t.self, capacity: Int(count)) {
host_info(mach_host_self(), HOST_BASIC_INFO, $0, &count)
host_info(initHostPort, HOST_BASIC_INFO, $0, &count)
}
}
mach_port_deallocate(mach_task_self_, initHostPort)
if result == KERN_SUCCESS {
return UInt64(stats.max_mem)
}
@ -786,7 +792,7 @@ class StatsManager: ObservableObject {
let result = withUnsafeMutablePointer(to: &info) {
$0.withMemoryRebound(to: integer_t.self, capacity: Int(count)) {
host_statistics(mach_host_self(), HOST_CPU_LOAD_INFO, $0, &count)
host_statistics(hostPort, HOST_CPU_LOAD_INFO, $0, &count)
}
}
@ -858,7 +864,7 @@ class StatsManager: ObservableObject {
let vmResult = withUnsafeMutablePointer(to: &vmStatistics) {
$0.withMemoryRebound(to: integer_t.self, capacity: Int(size)) {
host_statistics64(mach_host_self(), HOST_VM_INFO64, $0, &size)
host_statistics64(hostPort, HOST_VM_INFO64, $0, &size)
}
}
@ -978,7 +984,7 @@ class StatsManager: ObservableObject {
var cpuInfo: processor_info_array_t?
var numCpuInfo: mach_msg_type_number_t = 0
var numCPUsU: natural_t = 0
let result = host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &numCPUsU, &cpuInfo, &numCpuInfo)
let result = host_processor_info(hostPort, PROCESSOR_CPU_LOAD_INFO, &numCPUsU, &cpuInfo, &numCpuInfo)
guard result == KERN_SUCCESS, let cpuInfo else {
return cpuCoreUsage
}

View file

@ -128,13 +128,11 @@ enum AnimationLoopMode: String, Codable, CaseIterable {
enum AnimationSource: Codable, Hashable, Equatable {
case lottieFile(URL) // Local file (in app support or bundle)
case lottieURL(URL) // Remote URL
case builtInFace // Original MinimalFaceFeatures
var displayType: String {
switch self {
case .lottieFile: return "Local"
case .lottieURL: return "Remote"
case .builtInFace: return "Built-in"
}
}
}