Atoll/DynamicIsland/components/Stats/StatsPanel.swift
2025-09-22 00:39:40 +05:30

130 lines
4.1 KiB
Swift

//
// StatsPanel.swift
// DynamicIsland
//
// Created by Ebullioscopic on 13/08/25.
//
import AppKit
import SwiftUI
import Defaults
class StatsPanel: NSPanel {
init() {
super.init(
contentRect: .zero,
styleMask: [.borderless, .nonactivatingPanel],
backing: .buffered,
defer: true
)
setupWindow()
setupContentView()
}
// Override to allow the panel to become key window (required for user interaction)
override var canBecomeKey: Bool {
return true
}
// Override to allow the panel to become main window (required for text input and controls)
override var canBecomeMain: Bool {
return true
}
private func setupWindow() {
backgroundColor = .clear
isOpaque = false
hasShadow = true
level = .floating
isMovableByWindowBackground = true // Enable dragging
titlebarAppearsTransparent = true
titleVisibility = .hidden
isFloatingPanel = true // Mark as floating panel for proper behavior
// Allow dragging from any part of the window
styleMask.insert(.fullSizeContentView)
collectionBehavior = [
.canJoinAllSpaces,
.stationary,
.fullScreenAuxiliary // Float above full-screen apps
]
// Apply screen capture hiding setting
updateScreenCaptureVisibility()
setupScreenCaptureObserver()
// Accept mouse moved events for proper hover behavior
acceptsMouseMovedEvents = true
}
private func setupContentView() {
let contentView = StatsPanelView {
self.close()
}
let hostingView = NSHostingView(rootView: contentView)
self.contentView = hostingView
// Set initial size
let preferredSize = CGSize(width: 600, height: 400)
hostingView.setFrameSize(preferredSize)
setContentSize(preferredSize)
}
func positionNearNotch() {
guard let screen = NSScreen.main else { return }
let screenFrame = screen.visibleFrame
let panelFrame = frame
// Position at top center of screen (near where the notch would be)
let xPosition = (screenFrame.width - panelFrame.width) / 2 + screenFrame.minX
let yPosition = screenFrame.maxY - panelFrame.height - 10 // 10px from top
setFrameOrigin(NSPoint(x: xPosition, y: yPosition))
}
func positionNearMouse() {
let mouseLocation = NSEvent.mouseLocation
let panelFrame = frame
// Position near mouse but ensure it stays on screen
guard let screen = NSScreen.main else { return }
let screenFrame = screen.visibleFrame
var xPosition = mouseLocation.x - panelFrame.width / 2
var yPosition = mouseLocation.y - panelFrame.height - 20
// Keep within screen bounds
xPosition = max(screenFrame.minX + 10, min(xPosition, screenFrame.maxX - panelFrame.width - 10))
yPosition = max(screenFrame.minY + 10, min(yPosition, screenFrame.maxY - panelFrame.height - 10))
setFrameOrigin(NSPoint(x: xPosition, y: yPosition))
}
private func setupScreenCaptureObserver() {
// Observe changes to hidePanelsFromScreenCapture setting
Defaults.observe(.hidePanelsFromScreenCapture) { [weak self] change in
DispatchQueue.main.async {
self?.updateScreenCaptureVisibility()
}
}
}
private func updateScreenCaptureVisibility() {
let shouldHide = Defaults[.hidePanelsFromScreenCapture]
if shouldHide {
// Hide from screen capture and recording
self.sharingType = .none
print("🙈 StatsPanel: Hidden from screen capture and recordings")
} else {
// Allow normal screen capture
self.sharingType = .readOnly
print("👁️ StatsPanel: Visible in screen capture and recordings")
}
}
}