mirror of
https://github.com/FBukovina/Atoll.git
synced 2026-10-27 15:14:33 +00:00
HotFix: Remove Unnecessary Mach service for Stats
This commit is contained in:
parent
a2d18cda49
commit
28320e4cb8
11 changed files with 58 additions and 161 deletions
|
|
@ -433,7 +433,7 @@
|
|||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 8;
|
||||
CURRENT_PROJECT_VERSION = 9;
|
||||
DEVELOPMENT_ASSET_PATHS = "\"DynamicIsland/Preview Content\"";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
"DEVELOPMENT_TEAM[sdk=macosx*]" = 9Y64TRM77N;
|
||||
|
|
@ -505,7 +505,7 @@
|
|||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Developer ID Application";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 8;
|
||||
CURRENT_PROJECT_VERSION = 9;
|
||||
DEVELOPMENT_ASSET_PATHS = "\"DynamicIsland/Preview Content\"";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
"DEVELOPMENT_TEAM[sdk=macosx*]" = 9Y64TRM77N;
|
||||
|
|
|
|||
|
|
@ -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" : {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -170,17 +170,12 @@ 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
|
||||
))
|
||||
}
|
||||
}
|
||||
.frame(width: cropWidth * scale * previewScale, height: cropHeight * scale * previewScale)
|
||||
.offset(x: offsetX * previewScale, y: offsetY * previewScale)
|
||||
.rotationEffect(.degrees(rotation))
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue