🚀 First official release of ShotScreen with complete feature set: ✨ Core Features: - Advanced screenshot capture system - Multi-monitor support - Professional UI/UX design - Automated update system with Sparkle - Apple notarized & code signed 🛠 Technical Excellence: - Native Swift macOS application - Professional build & deployment pipeline - Comprehensive error handling - Memory optimized performance 📦 Distribution Ready: - Professional DMG packaging - Apple notarization complete - No security warnings for users - Ready for public distribution This is the foundation release that establishes ShotScreen as a premium screenshot tool for macOS.
176 lines
6.0 KiB
Swift
176 lines
6.0 KiB
Swift
import AppKit
|
|
import SwiftUI
|
|
|
|
// MARK: - Centralized Theme Manager
|
|
class ThemeManager {
|
|
static let shared = ThemeManager()
|
|
|
|
private init() {}
|
|
|
|
// MARK: - System-Aware Colors (automatic light/dark adaptation)
|
|
|
|
/// Background colors for containers (GLASS EFFECT zoals stash)
|
|
var containerBackground: NSColor {
|
|
// NIEUW: Glass effect achtergrond zoals stash window
|
|
// Gebruik transparante achtergrond zodat visual effect view erdoor kan
|
|
return NSColor.clear
|
|
}
|
|
|
|
/// Glass effect background for visual effect views
|
|
var glassEffectMaterial: NSVisualEffectView.Material {
|
|
return .hudWindow // Exact hetzelfde als stash window
|
|
}
|
|
|
|
/// Glass effect blending mode
|
|
var glassEffectBlending: NSVisualEffectView.BlendingMode {
|
|
return .behindWindow // Exact hetzelfde als stash window
|
|
}
|
|
|
|
/// Glass effect alpha
|
|
var glassEffectAlpha: CGFloat {
|
|
return 0.95 // Exact hetzelfde als stash window
|
|
}
|
|
|
|
/// Background colors for secondary containers
|
|
var secondaryContainerBackground: NSColor {
|
|
if NSApp.effectiveAppearance.name == NSAppearance.Name.darkAqua {
|
|
return NSColor(white: 0.42, alpha: 0.90) // Dark mode: iets lichter
|
|
} else {
|
|
return NSColor(white: 0.98, alpha: 0.90) // Light mode: bijna wit
|
|
}
|
|
}
|
|
|
|
/// Button and icon colors (adaptive)
|
|
var buttonTintColor: NSColor {
|
|
if NSApp.effectiveAppearance.name == NSAppearance.Name.darkAqua {
|
|
return NSColor(white: 0.95, alpha: 1.0) // Dark mode: wit
|
|
} else {
|
|
return NSColor(white: 0.25, alpha: 1.0) // Light mode: donkergrijs
|
|
}
|
|
}
|
|
|
|
/// Text colors (adaptive)
|
|
var primaryTextColor: NSColor {
|
|
if NSApp.effectiveAppearance.name == NSAppearance.Name.darkAqua {
|
|
return NSColor.white // Dark mode: wit
|
|
} else {
|
|
return NSColor.black // Light mode: zwart
|
|
}
|
|
}
|
|
|
|
var secondaryTextColor: NSColor {
|
|
if NSApp.effectiveAppearance.name == NSAppearance.Name.darkAqua {
|
|
return NSColor(white: 0.7, alpha: 1.0) // Dark mode: grijs
|
|
} else {
|
|
return NSColor(white: 0.4, alpha: 1.0) // Light mode: donkergrijs
|
|
}
|
|
}
|
|
|
|
/// Filename label text color (adaptive with opacity)
|
|
var filenameLabelTextColor: NSColor {
|
|
if NSApp.effectiveAppearance.name == NSAppearance.Name.darkAqua {
|
|
return NSColor(white: 0.7, alpha: 1.0) // Dark mode: lichtgrijs
|
|
} else {
|
|
return NSColor(white: 0.1, alpha: 1.0) // Light mode: veel donkerder voor betere zichtbaarheid
|
|
}
|
|
}
|
|
|
|
/// Grid cell icon background (adaptive)
|
|
var gridCellIconBackground: NSColor {
|
|
if NSApp.effectiveAppearance.name == NSAppearance.Name.darkAqua {
|
|
return NSColor.white.withAlphaComponent(0.25) // Dark mode
|
|
} else {
|
|
return NSColor.black.withAlphaComponent(0.25) // Light mode
|
|
}
|
|
}
|
|
|
|
/// Grid cell text color with hover effect
|
|
func gridCellTextColor(isHovered: Bool) -> NSColor {
|
|
if NSApp.effectiveAppearance.name == NSAppearance.Name.darkAqua {
|
|
return isHovered ? NSColor.white : NSColor.white.withAlphaComponent(0.1)
|
|
} else {
|
|
return isHovered ? NSColor.black : NSColor.black.withAlphaComponent(0.1)
|
|
}
|
|
}
|
|
|
|
// MARK: - Shadow Configuration (adaptive)
|
|
var shadowColor: NSColor {
|
|
if NSApp.effectiveAppearance.name == NSAppearance.Name.darkAqua {
|
|
return NSColor.black // Dark mode: black shadows
|
|
} else {
|
|
return NSColor.black.withAlphaComponent(0.3) // Light mode: lighter shadows
|
|
}
|
|
}
|
|
|
|
var shadowOpacity: Float {
|
|
if NSApp.effectiveAppearance.name == NSAppearance.Name.darkAqua {
|
|
return 0.50 // Dark mode: stronger shadows
|
|
} else {
|
|
return 0.25 // Light mode: subtle shadows
|
|
}
|
|
}
|
|
|
|
// MARK: - Utility Methods
|
|
|
|
/// Check if currently in dark mode
|
|
var isDarkMode: Bool {
|
|
return NSApp.effectiveAppearance.name == NSAppearance.Name.darkAqua
|
|
}
|
|
|
|
/// Debug function to print current theme info
|
|
func printCurrentTheme() {
|
|
let mode = isDarkMode ? "DARK" : "LIGHT"
|
|
print("🎨 THEME DEBUG: Current mode = \(mode)")
|
|
print("🎨 THEME DEBUG: Container background = GLASS EFFECT (\(glassEffectMaterial.rawValue))")
|
|
print("🎨 THEME DEBUG: Glass effect alpha = \(glassEffectAlpha)")
|
|
print("🎨 THEME DEBUG: Button tint = \(buttonTintColor)")
|
|
print("🎨 THEME DEBUG: Primary text = \(primaryTextColor)")
|
|
print("🎨 THEME DEBUG: Shadow opacity = \(shadowOpacity)")
|
|
}
|
|
|
|
/// Get hover color for buttons
|
|
var buttonHoverColor: NSColor {
|
|
if isDarkMode {
|
|
return NSColor.white
|
|
} else {
|
|
return NSColor.black
|
|
}
|
|
}
|
|
|
|
/// Get original button color (for hover restoration)
|
|
var buttonOriginalColor: NSColor {
|
|
return buttonTintColor
|
|
}
|
|
|
|
// MARK: - Notification for Theme Changes
|
|
func observeThemeChanges(callback: @escaping () -> Void) {
|
|
// Observer voor system appearance changes
|
|
DistributedNotificationCenter.default.addObserver(
|
|
forName: NSNotification.Name("AppleInterfaceThemeChangedNotification"),
|
|
object: nil,
|
|
queue: .main
|
|
) { _ in
|
|
print("🎨 THEME: System theme changed - notifying observers")
|
|
callback()
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - SwiftUI Color Extensions
|
|
extension Color {
|
|
static var adaptiveContainerBackground: Color {
|
|
Color(ThemeManager.shared.containerBackground)
|
|
}
|
|
|
|
static var adaptiveSecondaryBackground: Color {
|
|
Color(ThemeManager.shared.secondaryContainerBackground)
|
|
}
|
|
|
|
static var adaptivePrimaryText: Color {
|
|
Color(ThemeManager.shared.primaryTextColor)
|
|
}
|
|
|
|
static var adaptiveSecondaryText: Color {
|
|
Color(ThemeManager.shared.secondaryTextColor)
|
|
}
|
|
} |