🚀 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.
962 lines
42 KiB
Swift
962 lines
42 KiB
Swift
import AppKit
|
||
import SwiftUI // Needed for ObservableObject, Published, etc.
|
||
import Combine // Needed for objectWillChange
|
||
|
||
class SettingsManager: ObservableObject {
|
||
static let shared = SettingsManager()
|
||
private var isInitializing = false // NIEUWE FLAG
|
||
|
||
var screenshotFolder: String? {
|
||
get { UserDefaults.standard.string(forKey: SettingsKey.screenshotFolder) }
|
||
set {
|
||
objectWillChange.send()
|
||
UserDefaults.standard.set(newValue, forKey: SettingsKey.screenshotFolder)
|
||
}
|
||
}
|
||
|
||
var thumbnailTimer: Int {
|
||
get { UserDefaults.standard.integer(forKey: SettingsKey.thumbnailTimer) }
|
||
set { objectWillChange.send(); UserDefaults.standard.set(newValue, forKey: SettingsKey.thumbnailTimer) }
|
||
}
|
||
|
||
@Published var closeAfterDrag: Bool = false {
|
||
didSet {
|
||
UserDefaults.standard.set(closeAfterDrag, forKey: SettingsKey.closeAfterDrag)
|
||
if !isInitializing {
|
||
NotificationCenter.default.post(name: .closeAfterDragSettingChanged, object: nil)
|
||
}
|
||
}
|
||
}
|
||
|
||
var showFolderButton: Bool {
|
||
get { UserDefaults.standard.bool(forKey: SettingsKey.showFolderButton) }
|
||
set { objectWillChange.send(); UserDefaults.standard.set(newValue, forKey: SettingsKey.showFolderButton) }
|
||
}
|
||
|
||
@Published var closeAfterSave: Bool = false {
|
||
didSet {
|
||
UserDefaults.standard.set(closeAfterSave, forKey: SettingsKey.closeAfterSave)
|
||
if !isInitializing {
|
||
NotificationCenter.default.post(name: .closeAfterSaveSettingChanged, object: nil)
|
||
}
|
||
}
|
||
}
|
||
|
||
@Published var playSoundOnCapture: Bool = true {
|
||
didSet {
|
||
UserDefaults.standard.set(playSoundOnCapture, forKey: SettingsKey.playSoundOnCapture)
|
||
if !isInitializing { // CONTROLEER FLAG
|
||
NotificationCenter.default.post(name: .playSoundOnCaptureSettingChanged, object: nil)
|
||
}
|
||
}
|
||
}
|
||
|
||
// NEW: Properties for filename format
|
||
var filenamePrefix: String {
|
||
get { UserDefaults.standard.string(forKey: SettingsKey.filenamePrefix) ?? "Schermafbeelding" } // Default prefix
|
||
set { objectWillChange.send(); UserDefaults.standard.set(newValue, forKey: SettingsKey.filenamePrefix) }
|
||
}
|
||
|
||
var filenameFormatPreset: FilenameFormatPreset {
|
||
get {
|
||
let rawValue = UserDefaults.standard.integer(forKey: SettingsKey.filenameFormatPreset)
|
||
return FilenameFormatPreset(rawValue: rawValue) ?? .macOSStyle // Default naar macOS style
|
||
}
|
||
set { objectWillChange.send(); UserDefaults.standard.set(newValue.rawValue, forKey: SettingsKey.filenameFormatPreset) }
|
||
}
|
||
|
||
var filenameCustomFormat: String {
|
||
get { UserDefaults.standard.string(forKey: SettingsKey.filenameCustomFormat) ?? "{YYYY}-{MM}-{DD}_{hh}.{mm}.{ss}" } // Default custom format
|
||
set { objectWillChange.send(); UserDefaults.standard.set(newValue, forKey: SettingsKey.filenameCustomFormat) }
|
||
}
|
||
|
||
// NEW: Properties for action enables
|
||
var isRenameActionEnabled: Bool {
|
||
get {
|
||
let value = UserDefaults.standard.object(forKey: SettingsKey.isRenameActionEnabled) as? Bool ?? true
|
||
return value
|
||
}
|
||
set {
|
||
objectWillChange.send()
|
||
UserDefaults.standard.set(newValue, forKey: SettingsKey.isRenameActionEnabled)
|
||
}
|
||
}
|
||
var isStashActionEnabled: Bool {
|
||
get {
|
||
let value = UserDefaults.standard.object(forKey: SettingsKey.isStashActionEnabled) as? Bool ?? true
|
||
return value
|
||
}
|
||
set {
|
||
objectWillChange.send()
|
||
UserDefaults.standard.set(newValue, forKey: SettingsKey.isStashActionEnabled)
|
||
}
|
||
}
|
||
var isOCRActionEnabled: Bool {
|
||
get {
|
||
let value = UserDefaults.standard.object(forKey: SettingsKey.isOCRActionEnabled) as? Bool ?? true
|
||
return value
|
||
}
|
||
set {
|
||
objectWillChange.send()
|
||
UserDefaults.standard.set(newValue, forKey: SettingsKey.isOCRActionEnabled)
|
||
}
|
||
}
|
||
var isClipboardActionEnabled: Bool {
|
||
get {
|
||
let value = UserDefaults.standard.object(forKey: SettingsKey.isClipboardActionEnabled) as? Bool ?? true
|
||
return value
|
||
}
|
||
set {
|
||
objectWillChange.send()
|
||
UserDefaults.standard.set(newValue, forKey: SettingsKey.isClipboardActionEnabled)
|
||
}
|
||
}
|
||
var isBackgroundRemoveActionEnabled: Bool {
|
||
get {
|
||
let value = UserDefaults.standard.object(forKey: SettingsKey.isBackgroundRemoveActionEnabled) as? Bool ?? true
|
||
return value
|
||
}
|
||
set {
|
||
objectWillChange.send()
|
||
UserDefaults.standard.set(newValue, forKey: SettingsKey.isBackgroundRemoveActionEnabled)
|
||
}
|
||
}
|
||
var isCancelActionEnabled: Bool {
|
||
get {
|
||
let value = UserDefaults.standard.object(forKey: SettingsKey.isCancelActionEnabled) as? Bool ?? true
|
||
return value
|
||
}
|
||
set {
|
||
objectWillChange.send()
|
||
UserDefaults.standard.set(newValue, forKey: SettingsKey.isCancelActionEnabled)
|
||
}
|
||
}
|
||
var isRemoveActionEnabled: Bool {
|
||
get {
|
||
let value = UserDefaults.standard.object(forKey: SettingsKey.isRemoveActionEnabled) as? Bool ?? true
|
||
return value
|
||
}
|
||
set {
|
||
objectWillChange.send()
|
||
UserDefaults.standard.set(newValue, forKey: SettingsKey.isRemoveActionEnabled)
|
||
}
|
||
}
|
||
var isAction3Enabled: Bool {
|
||
get {
|
||
let value = UserDefaults.standard.object(forKey: SettingsKey.isAction3Enabled) as? Bool ?? false
|
||
return value
|
||
}
|
||
set {
|
||
objectWillChange.send()
|
||
UserDefaults.standard.set(newValue, forKey: SettingsKey.isAction3Enabled)
|
||
}
|
||
}
|
||
var isAction4Enabled: Bool {
|
||
get {
|
||
let value = UserDefaults.standard.object(forKey: SettingsKey.isAction4Enabled) as? Bool ?? false
|
||
return value
|
||
}
|
||
set {
|
||
objectWillChange.send()
|
||
UserDefaults.standard.set(newValue, forKey: SettingsKey.isAction4Enabled)
|
||
}
|
||
}
|
||
|
||
// NEW: Properties for Delete and Cancel Drag actions
|
||
var isDeleteActionEnabled: Bool {
|
||
get { UserDefaults.standard.object(forKey: SettingsKey.isDeleteActionEnabled) as? Bool ?? true } // Default AAN
|
||
set { objectWillChange.send(); UserDefaults.standard.set(newValue, forKey: SettingsKey.isDeleteActionEnabled) }
|
||
}
|
||
var isCancelDragActionEnabled: Bool {
|
||
get { UserDefaults.standard.object(forKey: SettingsKey.isCancelDragActionEnabled) as? Bool ?? true } // Default AAN
|
||
set { objectWillChange.send(); UserDefaults.standard.set(newValue, forKey: SettingsKey.isCancelDragActionEnabled) }
|
||
}
|
||
|
||
// 🎨 Background Removal Method Preference
|
||
var preferredBackgroundRemovalMethod: BackgroundRemovalMethod {
|
||
get {
|
||
let rawValue = UserDefaults.standard.string(forKey: SettingsKey.preferredBackgroundRemovalMethod) ?? "auto"
|
||
return BackgroundRemovalMethod(rawValue: rawValue) ?? .auto
|
||
}
|
||
set {
|
||
objectWillChange.send()
|
||
UserDefaults.standard.set(newValue.rawValue, forKey: SettingsKey.preferredBackgroundRemovalMethod)
|
||
}
|
||
}
|
||
|
||
// NEW: Property for automatic startup
|
||
@Published var startAppOnLogin: Bool = false {
|
||
didSet {
|
||
UserDefaults.standard.set(startAppOnLogin, forKey: SettingsKey.startAppOnLogin)
|
||
if !isInitializing {
|
||
NotificationCenter.default.post(name: .startAppOnLoginSettingChanged, object: nil)
|
||
}
|
||
}
|
||
}
|
||
|
||
// NEW: Property for automatic screenshot saving
|
||
var autoSaveScreenshot: Bool {
|
||
get { UserDefaults.standard.object(forKey: SettingsKey.autoSaveScreenshot) as? Bool ?? false } // Default false (handmatig beslissen)
|
||
set {
|
||
objectWillChange.send()
|
||
UserDefaults.standard.set(newValue, forKey: SettingsKey.autoSaveScreenshot)
|
||
// Optioneel: post een notificatie als directe actie in ScreenshotApp nodig is
|
||
// NotificationCenter.default.post(name: .autoSaveScreenshotChanged, object: nil)
|
||
}
|
||
}
|
||
|
||
// VOEG DEZE TOE
|
||
static let thumbnailFixedSizeKey = "thumbnailFixedSize"
|
||
@Published var thumbnailFixedSize: ThumbnailFixedSize = .medium {
|
||
didSet {
|
||
UserDefaults.standard.set(thumbnailFixedSize.rawValue, forKey: SettingsManager.thumbnailFixedSizeKey)
|
||
if !isInitializing {
|
||
NotificationCenter.default.post(name: .thumbnailSizeSettingChanged, object: nil)
|
||
}
|
||
}
|
||
}
|
||
|
||
// NEW: Property for stash always on top
|
||
@Published var stashAlwaysOnTop: Bool = false {
|
||
didSet {
|
||
UserDefaults.standard.set(stashAlwaysOnTop, forKey: SettingsKey.stashAlwaysOnTop)
|
||
if !isInitializing {
|
||
NotificationCenter.default.post(name: .stashAlwaysOnTopSettingChanged, object: nil)
|
||
}
|
||
}
|
||
}
|
||
|
||
// 🔥💎 MEGA NIEUWE STASH PREVIEW SIZE SETTING! 💎🔥
|
||
@Published var stashPreviewSize: StashPreviewSize = .medium {
|
||
didSet {
|
||
UserDefaults.standard.set(stashPreviewSize.rawValue, forKey: SettingsKey.stashPreviewSize)
|
||
if !isInitializing {
|
||
NotificationCenter.default.post(name: .stashPreviewSizeChanged, object: nil)
|
||
}
|
||
}
|
||
}
|
||
|
||
// 🔥💥⚡ HYPERMODE STASH GRID CONFIGURATION! ⚡💥🔥
|
||
@Published var stashGridMode: StashGridMode = .fixedColumns {
|
||
didSet {
|
||
UserDefaults.standard.set(stashGridMode.rawValue, forKey: SettingsKey.stashGridMode)
|
||
if !isInitializing {
|
||
NotificationCenter.default.post(name: .stashGridModeChanged, object: nil)
|
||
NotificationCenter.default.post(name: .stashGridConfigChanged, object: nil)
|
||
}
|
||
}
|
||
}
|
||
|
||
@Published var stashMaxColumns: Int = 2 {
|
||
didSet {
|
||
// Clamp to 1-5 range for HYPERMODE safety!
|
||
let clampedValue = max(1, min(5, stashMaxColumns))
|
||
if clampedValue != stashMaxColumns {
|
||
stashMaxColumns = clampedValue
|
||
return
|
||
}
|
||
UserDefaults.standard.set(stashMaxColumns, forKey: SettingsKey.stashMaxColumns)
|
||
if !isInitializing {
|
||
NotificationCenter.default.post(name: .stashGridConfigChanged, object: nil)
|
||
}
|
||
}
|
||
}
|
||
|
||
@Published var stashMaxRows: Int = 1 {
|
||
didSet {
|
||
// Clamp to 1-5 range for HYPERMODE safety!
|
||
let clampedValue = max(1, min(5, stashMaxRows))
|
||
if clampedValue != stashMaxRows {
|
||
stashMaxRows = clampedValue
|
||
return
|
||
}
|
||
UserDefaults.standard.set(stashMaxRows, forKey: SettingsKey.stashMaxRows)
|
||
if !isInitializing {
|
||
NotificationCenter.default.post(name: .stashGridConfigChanged, object: nil)
|
||
}
|
||
}
|
||
}
|
||
|
||
// 🔥 NIEUW: Persistent stash setting
|
||
@Published var persistentStash: Bool = false {
|
||
didSet {
|
||
UserDefaults.standard.set(persistentStash, forKey: SettingsKey.persistentStash)
|
||
if !isInitializing {
|
||
NotificationCenter.default.post(name: .persistentStashChanged, object: nil)
|
||
}
|
||
}
|
||
}
|
||
|
||
// 🔄 UPDATE SETTINGS
|
||
@Published var automaticUpdates: Bool = true {
|
||
didSet {
|
||
UserDefaults.standard.set(automaticUpdates, forKey: SettingsKey.automaticUpdates)
|
||
}
|
||
}
|
||
|
||
@Published var includePreReleases: Bool = false {
|
||
didSet {
|
||
UserDefaults.standard.set(includePreReleases, forKey: SettingsKey.includePreReleases)
|
||
}
|
||
}
|
||
|
||
// NEW: Property for hiding desktop icons during screenshots
|
||
@Published var hideDesktopIconsDuringScreenshot: Bool = false {
|
||
didSet {
|
||
UserDefaults.standard.set(hideDesktopIconsDuringScreenshot, forKey: SettingsKey.hideDesktopIconsDuringScreenshot)
|
||
if !isInitializing {
|
||
NotificationCenter.default.post(name: .hideDesktopIconsSettingChanged, object: nil)
|
||
}
|
||
print("Setting updated: hideDesktopIconsDuringScreenshot = \(hideDesktopIconsDuringScreenshot)")
|
||
}
|
||
}
|
||
|
||
// NEW: Property for hiding desktop widgets during screenshots
|
||
@Published var hideDesktopWidgetsDuringScreenshot: Bool = false {
|
||
didSet {
|
||
UserDefaults.standard.set(hideDesktopWidgetsDuringScreenshot, forKey: SettingsKey.hideDesktopWidgetsDuringScreenshot)
|
||
if !isInitializing {
|
||
NotificationCenter.default.post(name: .hideDesktopWidgetsSettingChanged, object: nil)
|
||
}
|
||
print("Setting updated: hideDesktopWidgetsDuringScreenshot = \(hideDesktopWidgetsDuringScreenshot)")
|
||
}
|
||
}
|
||
|
||
// 🔊 NEW: Sound volume and type settings
|
||
@Published var screenshotSoundVolume: Float = 0.1 {
|
||
didSet {
|
||
UserDefaults.standard.set(screenshotSoundVolume, forKey: SettingsKey.screenshotSoundVolume)
|
||
}
|
||
}
|
||
|
||
@Published var screenshotSoundType: ScreenshotSoundType = .pop {
|
||
didSet {
|
||
if let data = try? JSONEncoder().encode(screenshotSoundType) {
|
||
UserDefaults.standard.set(data, forKey: SettingsKey.screenshotSoundType)
|
||
}
|
||
}
|
||
}
|
||
|
||
// 🗂️ NEW: Cache management settings
|
||
@Published var cacheRetentionTime: CacheRetentionTime = .oneWeek {
|
||
didSet {
|
||
if let data = try? JSONEncoder().encode(cacheRetentionTime) {
|
||
UserDefaults.standard.set(data, forKey: SettingsKey.cacheRetentionTime)
|
||
}
|
||
// 🧪 NIEUW: Send notification for cache retention time changes (except during initialization)
|
||
if !isInitializing {
|
||
NotificationCenter.default.post(name: NSNotification.Name("cacheRetentionTimeChanged"), object: nil)
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
// NEW: Property for first launch completion
|
||
var hasCompletedFirstLaunch: Bool {
|
||
get { UserDefaults.standard.bool(forKey: SettingsKey.hasCompletedFirstLaunch) }
|
||
set {
|
||
objectWillChange.send()
|
||
UserDefaults.standard.set(newValue, forKey: SettingsKey.hasCompletedFirstLaunch)
|
||
}
|
||
}
|
||
|
||
var windowCaptureIncludeCursor: Bool {
|
||
get { UserDefaults.standard.bool(forKey: SettingsKey.windowCaptureIncludeCursor) }
|
||
set {
|
||
objectWillChange.send()
|
||
UserDefaults.standard.set(newValue, forKey: SettingsKey.windowCaptureIncludeCursor)
|
||
if !isInitializing {
|
||
NotificationCenter.default.post(name: .windowCaptureSettingChanged, object: nil)
|
||
}
|
||
}
|
||
}
|
||
|
||
// NEW: Property for clean desktop screenshots
|
||
// VERWIJDERD: cleanDesktopScreenshots property - feature disabled
|
||
|
||
@Published var saveAfterEdit: Bool = false {
|
||
didSet {
|
||
UserDefaults.standard.set(saveAfterEdit, forKey: SettingsKey.saveAfterEdit)
|
||
NotificationCenter.default.post(name: .saveAfterEditSettingChanged, object: nil)
|
||
}
|
||
}
|
||
|
||
var thumbnailDisplayScreen: ThumbnailDisplayScreen {
|
||
get {
|
||
let rawValue = UserDefaults.standard.string(forKey: SettingsKey.thumbnailDisplayScreen) ?? ThumbnailDisplayScreen.automatic.rawValue
|
||
return ThumbnailDisplayScreen(rawValue: rawValue) ?? .automatic
|
||
}
|
||
set {
|
||
objectWillChange.send()
|
||
UserDefaults.standard.set(newValue.rawValue, forKey: SettingsKey.thumbnailDisplayScreen)
|
||
}
|
||
}
|
||
|
||
static let actionOrderKey = "actionOrder"
|
||
@Published var actionOrder: [ActionType] = [] {
|
||
didSet {
|
||
let orderStrings = actionOrder.map { $0.rawValue }
|
||
UserDefaults.standard.set(orderStrings, forKey: SettingsManager.actionOrderKey)
|
||
}
|
||
}
|
||
|
||
// NEW: Keyboard shortcut properties
|
||
@Published var useCustomShortcut: Bool = false {
|
||
didSet {
|
||
UserDefaults.standard.set(useCustomShortcut, forKey: SettingsKey.useCustomShortcut)
|
||
if !isInitializing {
|
||
// Post notification for hotkey change
|
||
NotificationCenter.default.post(name: .shortcutSettingChanged, object: nil)
|
||
}
|
||
}
|
||
}
|
||
|
||
@Published var customShortcutModifiers: UInt = 0 {
|
||
didSet {
|
||
UserDefaults.standard.set(customShortcutModifiers, forKey: SettingsKey.customShortcutModifiers)
|
||
if !isInitializing && useCustomShortcut {
|
||
NotificationCenter.default.post(name: .shortcutSettingChanged, object: nil)
|
||
}
|
||
}
|
||
}
|
||
|
||
@Published var customShortcutKey: UInt16 = 0 {
|
||
didSet {
|
||
UserDefaults.standard.set(customShortcutKey, forKey: SettingsKey.customShortcutKey)
|
||
if !isInitializing && useCustomShortcut {
|
||
NotificationCenter.default.post(name: .shortcutSettingChanged, object: nil)
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
private init() {
|
||
isInitializing = true // ZET FLAG
|
||
|
||
// Laad ALLE properties hier uit UserDefaults
|
||
self.screenshotFolder = UserDefaults.standard.string(forKey: SettingsKey.screenshotFolder) // Kan nil zijn
|
||
self.filenamePrefix = UserDefaults.standard.string(forKey: SettingsKey.filenamePrefix) ?? "Schermafbeelding"
|
||
|
||
let presetRaw = UserDefaults.standard.integer(forKey: SettingsKey.filenameFormatPreset)
|
||
self.filenameFormatPreset = FilenameFormatPreset(rawValue: presetRaw) ?? .macOSStyle
|
||
// Als de opgeslagen rawValue 0 was en .macOSStyle is 0, dan is dit onnodig dubbel.
|
||
// Overweeg: if UserDefaults.standard.object(forKey: SettingsKey.filenameFormatPreset) != nil { ... laden ... } else { default }
|
||
|
||
self.filenameCustomFormat = UserDefaults.standard.string(forKey: SettingsKey.filenameCustomFormat) ?? "{YYYY}-{MM}-{DD}_{hh}.{mm}.{ss}"
|
||
self.saveAfterEdit = UserDefaults.standard.bool(forKey: SettingsKey.saveAfterEdit) // Default false als key niet bestaat
|
||
self.playSoundOnCapture = UserDefaults.standard.object(forKey: SettingsKey.playSoundOnCapture) as? Bool ?? true
|
||
self.thumbnailTimer = UserDefaults.standard.integer(forKey: SettingsKey.thumbnailTimer)
|
||
self.closeAfterDrag = UserDefaults.standard.bool(forKey: SettingsKey.closeAfterDrag)
|
||
|
||
let thumbFixedSizeKeyString = SettingsManager.thumbnailFixedSizeKey
|
||
let loadedFixedSizeRawValue = UserDefaults.standard.string(forKey: thumbFixedSizeKeyString)
|
||
if let loadedSize = loadedFixedSizeRawValue.flatMap(ThumbnailFixedSize.init) {
|
||
if self.thumbnailFixedSize != loadedSize {
|
||
self.thumbnailFixedSize = loadedSize
|
||
}
|
||
} else {
|
||
UserDefaults.standard.set(ThumbnailFixedSize.medium.rawValue, forKey: thumbFixedSizeKeyString)
|
||
}
|
||
|
||
self.showFolderButton = UserDefaults.standard.object(forKey: SettingsKey.showFolderButton) as? Bool ?? true
|
||
self.startAppOnLogin = UserDefaults.standard.object(forKey: SettingsKey.startAppOnLogin) as? Bool ?? false
|
||
self.autoSaveScreenshot = UserDefaults.standard.object(forKey: SettingsKey.autoSaveScreenshot) as? Bool ?? false
|
||
self.closeAfterSave = UserDefaults.standard.bool(forKey: SettingsKey.closeAfterSave)
|
||
|
||
// Stash window border etc. ook hier initialiseren:
|
||
// self.stashWindowBorderWidth = UserDefaults.standard.object(forKey: SettingsKey.stashWindowBorderWidth) == nil ? 1.0 : CGFloat(UserDefaults.standard.float(forKey: SettingsKey.stashWindowBorderWidth))
|
||
self.isRenameActionEnabled = UserDefaults.standard.object(forKey: SettingsKey.isRenameActionEnabled) as? Bool ?? true
|
||
self.isStashActionEnabled = UserDefaults.standard.object(forKey: SettingsKey.isStashActionEnabled) as? Bool ?? true
|
||
self.isOCRActionEnabled = UserDefaults.standard.object(forKey: SettingsKey.isOCRActionEnabled) as? Bool ?? true
|
||
self.isClipboardActionEnabled = UserDefaults.standard.object(forKey: SettingsKey.isClipboardActionEnabled) as? Bool ?? true
|
||
self.isBackgroundRemoveActionEnabled = UserDefaults.standard.object(forKey: SettingsKey.isBackgroundRemoveActionEnabled) as? Bool ?? true
|
||
self.isCancelActionEnabled = UserDefaults.standard.object(forKey: SettingsKey.isCancelActionEnabled) as? Bool ?? true
|
||
self.isRemoveActionEnabled = UserDefaults.standard.object(forKey: SettingsKey.isRemoveActionEnabled) as? Bool ?? true
|
||
self.isDeleteActionEnabled = UserDefaults.standard.object(forKey: SettingsKey.isDeleteActionEnabled) as? Bool ?? true
|
||
self.isCancelDragActionEnabled = UserDefaults.standard.object(forKey: SettingsKey.isCancelDragActionEnabled) as? Bool ?? true
|
||
self.stashAlwaysOnTop = UserDefaults.standard.object(forKey: SettingsKey.stashAlwaysOnTop) as? Bool ?? false
|
||
self.hideDesktopIconsDuringScreenshot = UserDefaults.standard.object(forKey: SettingsKey.hideDesktopIconsDuringScreenshot) as? Bool ?? false
|
||
self.hideDesktopWidgetsDuringScreenshot = UserDefaults.standard.object(forKey: SettingsKey.hideDesktopWidgetsDuringScreenshot) as? Bool ?? false
|
||
|
||
|
||
// 🔥💎 MEGA NIEUWE STASH PREVIEW SIZE INIT! 💎🔥
|
||
let stashPreviewSizeRaw = UserDefaults.standard.string(forKey: SettingsKey.stashPreviewSize) ?? StashPreviewSize.medium.rawValue
|
||
self.stashPreviewSize = StashPreviewSize(rawValue: stashPreviewSizeRaw) ?? .medium
|
||
|
||
// 🔥💥⚡ HYPERMODE STASH GRID INIT! ⚡💥🔥
|
||
let stashGridModeRaw = UserDefaults.standard.string(forKey: SettingsKey.stashGridMode) ?? StashGridMode.fixedColumns.rawValue
|
||
self.stashGridMode = StashGridMode(rawValue: stashGridModeRaw) ?? .fixedColumns
|
||
|
||
self.stashMaxColumns = UserDefaults.standard.object(forKey: SettingsKey.stashMaxColumns) as? Int ?? 2
|
||
// HYPERMODE SAFETY: Clamp to 1-5 range!
|
||
self.stashMaxColumns = max(1, min(5, self.stashMaxColumns))
|
||
|
||
self.stashMaxRows = UserDefaults.standard.object(forKey: SettingsKey.stashMaxRows) as? Int ?? 1
|
||
// HYPERMODE SAFETY: Clamp to 1-5 range!
|
||
self.stashMaxRows = max(1, min(5, self.stashMaxRows))
|
||
|
||
// 🔥 NIEUW: Persistent stash init
|
||
self.persistentStash = UserDefaults.standard.object(forKey: SettingsKey.persistentStash) as? Bool ?? false
|
||
|
||
// 🔄 UPDATE SETTINGS INIT
|
||
self.automaticUpdates = UserDefaults.standard.object(forKey: SettingsKey.automaticUpdates) as? Bool ?? true
|
||
self.includePreReleases = UserDefaults.standard.object(forKey: SettingsKey.includePreReleases) as? Bool ?? false
|
||
|
||
// 🎹 CUSTOM SHORTCUT SETTINGS INIT
|
||
self.useCustomShortcut = UserDefaults.standard.object(forKey: SettingsKey.useCustomShortcut) as? Bool ?? false
|
||
self.customShortcutModifiers = UserDefaults.standard.object(forKey: SettingsKey.customShortcutModifiers) as? UInt ?? 0
|
||
self.customShortcutKey = UserDefaults.standard.object(forKey: SettingsKey.customShortcutKey) as? UInt16 ?? 0
|
||
|
||
// 🔊 SOUND SETTINGS INIT
|
||
self.screenshotSoundVolume = UserDefaults.standard.object(forKey: SettingsKey.screenshotSoundVolume) as? Float ?? 0.1
|
||
|
||
if let soundTypeData = UserDefaults.standard.data(forKey: SettingsKey.screenshotSoundType),
|
||
let soundType = try? JSONDecoder().decode(ScreenshotSoundType.self, from: soundTypeData) {
|
||
self.screenshotSoundType = soundType
|
||
} else {
|
||
self.screenshotSoundType = .pop
|
||
}
|
||
|
||
// 🗂️ CACHE MANAGEMENT INIT
|
||
if let cacheRetentionData = UserDefaults.standard.data(forKey: SettingsKey.cacheRetentionTime),
|
||
let retentionTime = try? JSONDecoder().decode(CacheRetentionTime.self, from: cacheRetentionData) {
|
||
self.cacheRetentionTime = retentionTime
|
||
} else {
|
||
self.cacheRetentionTime = .oneWeek
|
||
}
|
||
|
||
// Initialize thumbnailDisplayScreen
|
||
let _ = UserDefaults.standard.string(forKey: SettingsKey.thumbnailDisplayScreen) ?? ThumbnailDisplayScreen.automatic.rawValue
|
||
// No need to set it since it's a computed property
|
||
|
||
// Load action order with migration for new actions
|
||
if let savedOrder = UserDefaults.standard.stringArray(forKey: SettingsManager.actionOrderKey) {
|
||
var loadedOrder = savedOrder.compactMap { ActionType(rawValue: $0) }
|
||
|
||
// Migration: ensure all new actions are included
|
||
let allActions = ActionType.allCases
|
||
for action in allActions {
|
||
if !loadedOrder.contains(action) {
|
||
loadedOrder.append(action)
|
||
}
|
||
}
|
||
|
||
actionOrder = loadedOrder
|
||
} else {
|
||
actionOrder = ActionType.allCases
|
||
}
|
||
|
||
// Initialize hasCompletedFirstLaunch
|
||
self.hasCompletedFirstLaunch = UserDefaults.standard.object(forKey: SettingsKey.hasCompletedFirstLaunch) as? Bool ?? false
|
||
|
||
isInitializing = false // RESET FLAG
|
||
}
|
||
|
||
private enum CodingKeys: String, CodingKey {
|
||
case screenshotFolder
|
||
case filenamePrefix
|
||
case filenameFormatPreset
|
||
case filenameCustomFormat
|
||
case saveAfterEdit
|
||
case playSoundOnCapture
|
||
case thumbnailTimer
|
||
case closeAfterDrag
|
||
case thumbnailFixedSize
|
||
case showFolderButton
|
||
case startAppOnLogin
|
||
case autoSaveScreenshot
|
||
case closeAfterSave
|
||
}
|
||
|
||
required init(from decoder: Decoder) throws {
|
||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||
screenshotFolder = try container.decodeIfPresent(String.self, forKey: .screenshotFolder)
|
||
filenamePrefix = try container.decodeIfPresent(String.self, forKey: .filenamePrefix) ?? "Screenshot"
|
||
filenameCustomFormat = try container.decodeIfPresent(String.self, forKey: .filenameCustomFormat) ?? "{YYYY}-{MM}-{DD}_{hh}.{mm}.{ss}"
|
||
saveAfterEdit = try container.decodeIfPresent(Bool.self, forKey: .saveAfterEdit) ?? false
|
||
playSoundOnCapture = try container.decodeIfPresent(Bool.self, forKey: .playSoundOnCapture) ?? true
|
||
thumbnailTimer = try container.decodeIfPresent(Int.self, forKey: .thumbnailTimer) ?? 0
|
||
closeAfterDrag = try container.decodeIfPresent(Bool.self, forKey: .closeAfterDrag) ?? false
|
||
let presetRaw = try container.decodeIfPresent(Int.self, forKey: .filenameFormatPreset) ?? FilenameFormatPreset.macOSStyle.rawValue
|
||
filenameFormatPreset = FilenameFormatPreset(rawValue: presetRaw) ?? .macOSStyle
|
||
thumbnailFixedSize = try container.decodeIfPresent(ThumbnailFixedSize.self, forKey: .thumbnailFixedSize) ?? .medium
|
||
showFolderButton = try container.decodeIfPresent(Bool.self, forKey: .showFolderButton) ?? true
|
||
startAppOnLogin = try container.decodeIfPresent(Bool.self, forKey: .startAppOnLogin) ?? false
|
||
autoSaveScreenshot = try container.decodeIfPresent(Bool.self, forKey: .autoSaveScreenshot) ?? false
|
||
closeAfterSave = try container.decodeIfPresent(Bool.self, forKey: .closeAfterSave) ?? false
|
||
}
|
||
|
||
func encode(to encoder: Encoder) throws {
|
||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||
try container.encode(screenshotFolder, forKey: .screenshotFolder)
|
||
try container.encode(filenamePrefix, forKey: .filenamePrefix)
|
||
try container.encode(filenameFormatPreset.rawValue, forKey: .filenameFormatPreset)
|
||
try container.encode(filenameCustomFormat, forKey: .filenameCustomFormat)
|
||
try container.encode(saveAfterEdit, forKey: .saveAfterEdit)
|
||
try container.encode(playSoundOnCapture, forKey: .playSoundOnCapture)
|
||
try container.encode(thumbnailTimer, forKey: .thumbnailTimer)
|
||
try container.encode(closeAfterDrag, forKey: .closeAfterDrag)
|
||
try container.encode(thumbnailFixedSize, forKey: .thumbnailFixedSize)
|
||
try container.encode(showFolderButton, forKey: .showFolderButton)
|
||
try container.encode(startAppOnLogin, forKey: .startAppOnLogin)
|
||
try container.encode(autoSaveScreenshot, forKey: .autoSaveScreenshot)
|
||
try container.encode(closeAfterSave, forKey: .closeAfterSave)
|
||
}
|
||
|
||
func resetToDefaults() {
|
||
objectWillChange.send() // Stuur eenmalig aan het begin
|
||
|
||
// Wijs defaults direct toe aan de properties; de didSets zorgen voor opslaan en notificaties.
|
||
screenshotFolder = defaultScreenshotFolder()
|
||
filenamePrefix = "Schermafbeelding"
|
||
filenameFormatPreset = .macOSStyle
|
||
filenameCustomFormat = "{YYYY}-{MM}-{DD}_{hh}.{mm}.{ss}"
|
||
saveAfterEdit = false
|
||
playSoundOnCapture = true
|
||
thumbnailTimer = 0
|
||
closeAfterDrag = false
|
||
thumbnailFixedSize = .medium
|
||
showFolderButton = true
|
||
startAppOnLogin = false
|
||
autoSaveScreenshot = false
|
||
closeAfterSave = false
|
||
isRenameActionEnabled = true
|
||
isStashActionEnabled = true
|
||
isOCRActionEnabled = true
|
||
isClipboardActionEnabled = true
|
||
isCancelActionEnabled = true
|
||
isRemoveActionEnabled = true
|
||
isDeleteActionEnabled = true
|
||
isCancelDragActionEnabled = true
|
||
stashAlwaysOnTop = false
|
||
hideDesktopIconsDuringScreenshot = false
|
||
|
||
// 🔥💎 MEGA NIEUWE RESET VOOR STASH PREVIEW SIZE! 💎🔥
|
||
stashPreviewSize = .medium
|
||
|
||
// 🔥💥⚡ HYPERMODE STASH GRID RESET! ⚡💥🔥
|
||
stashGridMode = .fixedColumns
|
||
stashMaxColumns = 2
|
||
stashMaxRows = 1
|
||
|
||
// 🔥 NIEUW: Reset persistent stash
|
||
persistentStash = false
|
||
|
||
// 🔄 RESET UPDATE SETTINGS
|
||
automaticUpdates = true
|
||
includePreReleases = false
|
||
|
||
// 🎹 RESET CUSTOM SHORTCUT SETTINGS
|
||
useCustomShortcut = false
|
||
customShortcutModifiers = 0
|
||
customShortcutKey = 0
|
||
|
||
|
||
// Verwijder de saveSettings() aanroep.
|
||
// Verwijder de individuele NotificationCenter.default.post calls hier; didSets handelen dat af.
|
||
}
|
||
|
||
private func defaultScreenshotFolder() -> String? {
|
||
// Voorbeeld: probeer ~/Pictures/Screenshots, anders nil
|
||
if let picturesURL = FileManager.default.urls(for: .picturesDirectory, in: .userDomainMask).first {
|
||
let screenshotsURL = picturesURL.appendingPathComponent("Screenshots")
|
||
// Maak de map als hij niet bestaat (optioneel)
|
||
// try? FileManager.default.createDirectory(at: screenshotsURL, withIntermediateDirectories: true, attributes: nil)
|
||
return screenshotsURL.path
|
||
}
|
||
return nil
|
||
}
|
||
|
||
func resetActionOrder() {
|
||
actionOrder = ActionType.allCases
|
||
}
|
||
|
||
func moveAction(_ action: ActionType, direction: Int) {
|
||
guard let currentIndex = actionOrder.firstIndex(of: action) else { return }
|
||
let newIndex = currentIndex + direction
|
||
|
||
guard newIndex >= 0 && newIndex < actionOrder.count else { return }
|
||
|
||
actionOrder.swapAt(currentIndex, newIndex)
|
||
}
|
||
|
||
// saveSettings() is waarschijnlijk niet nodig als @Published didSets goed werken.
|
||
// Als je het toch wilt:
|
||
/*
|
||
func saveSettings() {
|
||
UserDefaults.standard.set(screenshotFolder, forKey: SettingsKey.screenshotFolder)
|
||
// ... etc. voor alle settings ...
|
||
UserDefaults.standard.synchronize() // Optioneel, gebeurt periodiek
|
||
}
|
||
*/
|
||
}
|
||
|
||
// MARK: - Settings Window UI (Nieuwe structuur met TabView)
|
||
|
||
struct SettingsSnapshot {
|
||
var screenshotFolder: String?
|
||
var thumbnailTimer: Int
|
||
var closeAfterDrag: Bool
|
||
var thumbnailFixedSize: ThumbnailFixedSize
|
||
var showFolderButton: Bool
|
||
var closeAfterSave: Bool
|
||
var playSoundOnCapture: Bool
|
||
var filenamePrefix: String
|
||
var filenameFormatPreset: FilenameFormatPreset
|
||
var filenameCustomFormat: String
|
||
var startAppOnLogin: Bool
|
||
var autoSaveScreenshot: Bool
|
||
var thumbnailDisplayScreen: ThumbnailDisplayScreen
|
||
var stashAlwaysOnTop: Bool
|
||
var hideDesktopIconsDuringScreenshot: Bool
|
||
|
||
static func captureCurrent() -> SettingsSnapshot {
|
||
let s = SettingsManager.shared
|
||
return SettingsSnapshot(
|
||
screenshotFolder: s.screenshotFolder,
|
||
thumbnailTimer: s.thumbnailTimer,
|
||
closeAfterDrag: s.closeAfterDrag,
|
||
thumbnailFixedSize: s.thumbnailFixedSize,
|
||
showFolderButton: s.showFolderButton,
|
||
closeAfterSave: s.closeAfterSave,
|
||
playSoundOnCapture: s.playSoundOnCapture,
|
||
filenamePrefix: s.filenamePrefix,
|
||
filenameFormatPreset: s.filenameFormatPreset,
|
||
filenameCustomFormat: s.filenameCustomFormat,
|
||
startAppOnLogin: s.startAppOnLogin,
|
||
autoSaveScreenshot: s.autoSaveScreenshot,
|
||
thumbnailDisplayScreen: s.thumbnailDisplayScreen,
|
||
stashAlwaysOnTop: s.stashAlwaysOnTop,
|
||
hideDesktopIconsDuringScreenshot: s.hideDesktopIconsDuringScreenshot
|
||
)
|
||
}
|
||
|
||
func apply(to manager: SettingsManager = SettingsManager.shared) {
|
||
manager.screenshotFolder = screenshotFolder
|
||
manager.thumbnailTimer = thumbnailTimer
|
||
manager.closeAfterDrag = closeAfterDrag
|
||
manager.thumbnailFixedSize = thumbnailFixedSize
|
||
manager.showFolderButton = showFolderButton
|
||
manager.closeAfterSave = closeAfterSave
|
||
manager.playSoundOnCapture = playSoundOnCapture
|
||
manager.filenamePrefix = filenamePrefix
|
||
manager.filenameFormatPreset = filenameFormatPreset
|
||
manager.filenameCustomFormat = filenameCustomFormat
|
||
manager.startAppOnLogin = startAppOnLogin
|
||
manager.autoSaveScreenshot = autoSaveScreenshot
|
||
manager.thumbnailDisplayScreen = thumbnailDisplayScreen
|
||
manager.stashAlwaysOnTop = stashAlwaysOnTop
|
||
manager.hideDesktopIconsDuringScreenshot = hideDesktopIconsDuringScreenshot
|
||
}
|
||
}
|
||
|
||
// MARK: - Cache Manager
|
||
struct CacheManager {
|
||
static let shared = CacheManager()
|
||
|
||
private init() {}
|
||
|
||
// Get thumbnail directory path
|
||
private var thumbnailDirectory: URL {
|
||
let appSupportDirectory = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first!
|
||
let shotScreenDirectory = appSupportDirectory.appendingPathComponent("ShotScreen")
|
||
let thumbnailsDirectory = shotScreenDirectory.appendingPathComponent("Thumbnails")
|
||
return thumbnailsDirectory
|
||
}
|
||
|
||
// Calculate cache size in MB
|
||
func getCacheSize() -> Double {
|
||
do {
|
||
let contents = try FileManager.default.contentsOfDirectory(at: thumbnailDirectory, includingPropertiesForKeys: [.fileSizeKey], options: [])
|
||
|
||
var totalSize: Int64 = 0
|
||
for fileURL in contents {
|
||
// Skip thumbnail restoration directory from cache size calculation
|
||
if fileURL.lastPathComponent == "thumbnail_restoration" {
|
||
continue
|
||
}
|
||
|
||
do {
|
||
let resourceValues = try fileURL.resourceValues(forKeys: [.fileSizeKey])
|
||
if let fileSize = resourceValues.fileSize {
|
||
totalSize += Int64(fileSize)
|
||
}
|
||
} catch {
|
||
print("⚠️ Error getting file size for \(fileURL.lastPathComponent): \(error)")
|
||
}
|
||
}
|
||
|
||
// Convert bytes to MB
|
||
return Double(totalSize) / (1024 * 1024)
|
||
} catch {
|
||
print("⚠️ Error calculating cache size: \(error)")
|
||
return 0.0
|
||
}
|
||
}
|
||
|
||
// Get cache file count
|
||
func getCacheFileCount() -> Int {
|
||
do {
|
||
let contents = try FileManager.default.contentsOfDirectory(at: thumbnailDirectory, includingPropertiesForKeys: [.isDirectoryKey], options: [])
|
||
|
||
var fileCount = 0
|
||
for fileURL in contents {
|
||
// Skip thumbnail restoration directory
|
||
if fileURL.lastPathComponent == "thumbnail_restoration" {
|
||
continue
|
||
}
|
||
|
||
// Only count PNG files, not directories
|
||
let resourceValues = try? fileURL.resourceValues(forKeys: [.isDirectoryKey])
|
||
let isDirectory = resourceValues?.isDirectory ?? false
|
||
|
||
if !isDirectory && fileURL.pathExtension == "png" {
|
||
fileCount += 1
|
||
}
|
||
}
|
||
|
||
return fileCount
|
||
} catch {
|
||
print("⚠️ Error getting cache file count: \(error)")
|
||
return 0
|
||
}
|
||
}
|
||
|
||
// Clear all cache (except active thumbnails)
|
||
func clearCache(preserveActiveThumbnails: Bool = true) -> (deletedFiles: Int, savedSpace: Double) {
|
||
do {
|
||
let contents = try FileManager.default.contentsOfDirectory(at: thumbnailDirectory, includingPropertiesForKeys: [.fileSizeKey, .creationDateKey], options: [])
|
||
|
||
var deletedFiles = 0
|
||
var savedSpace: Int64 = 0
|
||
let activeThumbnailPath = getActiveThumbnailPath()
|
||
|
||
for fileURL in contents {
|
||
// Skip if this is the active thumbnail and we want to preserve it
|
||
if preserveActiveThumbnails && fileURL.path == activeThumbnailPath {
|
||
print("🔒 Preserving active thumbnail: \(fileURL.lastPathComponent)")
|
||
continue
|
||
}
|
||
|
||
// Skip thumbnail restoration directory completely
|
||
if fileURL.lastPathComponent == "thumbnail_restoration" {
|
||
print("🔒 Preserving thumbnail restoration directory: \(fileURL.lastPathComponent)")
|
||
continue
|
||
}
|
||
|
||
// Skip thumbnail restoration backup files
|
||
if fileURL.lastPathComponent.contains("latest_backup") {
|
||
print("🔒 Preserving thumbnail restoration backup file: \(fileURL.lastPathComponent)")
|
||
continue
|
||
}
|
||
|
||
do {
|
||
let resourceValues = try fileURL.resourceValues(forKeys: [.fileSizeKey])
|
||
let fileSize = resourceValues.fileSize ?? 0
|
||
|
||
try FileManager.default.removeItem(at: fileURL)
|
||
deletedFiles += 1
|
||
savedSpace += Int64(fileSize)
|
||
print("🗑️ Deleted cache file: \(fileURL.lastPathComponent)")
|
||
} catch {
|
||
print("⚠️ Failed to delete \(fileURL.lastPathComponent): \(error)")
|
||
}
|
||
}
|
||
|
||
let savedSpaceMB = Double(savedSpace) / (1024 * 1024)
|
||
print("✅ Cache cleanup complete: \(deletedFiles) files deleted, \(String(format: "%.1f", savedSpaceMB)) MB freed")
|
||
return (deletedFiles, savedSpaceMB)
|
||
|
||
} catch {
|
||
print("❌ Error during cache cleanup: \(error)")
|
||
return (0, 0.0)
|
||
}
|
||
}
|
||
|
||
// Clean cache based on retention time
|
||
func cleanupOldCache() {
|
||
let retentionTime = SettingsManager.shared.cacheRetentionTime
|
||
|
||
// Don't cleanup if retention is set to forever
|
||
guard let maxAge = retentionTime.timeInterval else {
|
||
print("🗂️ Cache retention set to forever - no automatic cleanup")
|
||
return
|
||
}
|
||
|
||
do {
|
||
let contents = try FileManager.default.contentsOfDirectory(at: thumbnailDirectory, includingPropertiesForKeys: [.creationDateKey, .fileSizeKey], options: [])
|
||
let cutoffDate = Date().addingTimeInterval(-maxAge)
|
||
let activeThumbnailPath = getActiveThumbnailPath()
|
||
|
||
print("🧪 CLEANUP: Checking \(contents.count) files. Cutoff time: \(cutoffDate). Max age: \(Int(maxAge))s")
|
||
|
||
var deletedFiles = 0
|
||
var savedSpace: Int64 = 0
|
||
var checkedFiles = 0
|
||
|
||
for fileURL in contents {
|
||
// Skip active thumbnail
|
||
if fileURL.path == activeThumbnailPath {
|
||
print("🧪 CLEANUP: Skipping active thumbnail: \(fileURL.lastPathComponent)")
|
||
continue
|
||
}
|
||
|
||
// Skip thumbnail restoration directory completely
|
||
if fileURL.lastPathComponent == "thumbnail_restoration" {
|
||
continue
|
||
}
|
||
|
||
// Skip thumbnail restoration backup files
|
||
if fileURL.lastPathComponent.contains("latest_backup") {
|
||
continue
|
||
}
|
||
|
||
do {
|
||
let resourceValues = try fileURL.resourceValues(forKeys: [.creationDateKey, .fileSizeKey])
|
||
|
||
if let creationDate = resourceValues.creationDate {
|
||
checkedFiles += 1
|
||
let age = Date().timeIntervalSince(creationDate)
|
||
print("🧪 CLEANUP: \(fileURL.lastPathComponent) - age: \(Int(age))s, created: \(creationDate)")
|
||
|
||
if creationDate < cutoffDate {
|
||
let fileSize = resourceValues.fileSize ?? 0
|
||
try FileManager.default.removeItem(at: fileURL)
|
||
deletedFiles += 1
|
||
savedSpace += Int64(fileSize)
|
||
print("🗑️ DELETED: \(fileURL.lastPathComponent) (was \(Int(age))s old)")
|
||
} else {
|
||
print("✅ KEEPING: \(fileURL.lastPathComponent) (only \(Int(age))s old)")
|
||
}
|
||
}
|
||
} catch {
|
||
print("⚠️ Error processing \(fileURL.lastPathComponent): \(error)")
|
||
}
|
||
}
|
||
|
||
if deletedFiles > 0 {
|
||
let savedSpaceMB = Double(savedSpace) / (1024 * 1024)
|
||
print("✅ Auto cache cleanup: \(deletedFiles) old files deleted, \(String(format: "%.1f", savedSpaceMB)) MB freed")
|
||
} else if checkedFiles > 0 {
|
||
print("🧪 CLEANUP: No files old enough to delete (\(checkedFiles) files checked)")
|
||
} else {
|
||
print("🧪 CLEANUP: No cache files found to check")
|
||
}
|
||
|
||
} catch {
|
||
print("❌ Error during automatic cache cleanup: \(error)")
|
||
}
|
||
}
|
||
|
||
// Get active thumbnail path (to avoid deleting currently open thumbnail)
|
||
private func getActiveThumbnailPath() -> String? {
|
||
// Try to get the active thumbnail URL from ScreenshotApp
|
||
if let app = NSApp.delegate as? ScreenshotApp,
|
||
let tempURL = app.getTempURL() {
|
||
return tempURL.path
|
||
}
|
||
return nil
|
||
}
|
||
} |