Files
shotscreen/ShotScreen/Sources/SettingsModels.swift
Nick Roodenrijs 0dabed11d2 🎉 ShotScreen v1.0 - Initial Release
🚀 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.
2025-06-28 16:15:15 +02:00

413 lines
15 KiB
Swift
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import AppKit
import SwiftUI // Needed for CGSize, CaseIterable, Identifiable, Codable
// Define Notification Names
extension Notification.Name {
static let closeAfterDragSettingChanged = Notification.Name("closeAfterDragSettingChanged")
static let closeAfterSaveSettingChanged = Notification.Name("closeAfterSaveSettingChanged")
static let playSoundOnCaptureSettingChanged = Notification.Name("playSoundOnCaptureSettingChanged")
static let startAppOnLoginSettingChanged = Notification.Name("startAppOnLoginSettingChanged")
static let thumbnailSizeSettingChanged = Notification.Name("thumbnailSizeSettingChanged")
static let screenshotFolderChanged = Notification.Name("screenshotFolderChanged")
static let filenameSettingsChanged = Notification.Name("filenameSettingsChanged")
static let saveAfterEditSettingChanged = Notification.Name("saveAfterEditSettingChanged")
static let thumbnailTimerSettingChanged = Notification.Name("thumbnailTimerSettingChanged")
static let thumbnailPositionSettingChanged = Notification.Name("thumbnailPositionSettingChanged")
static let showFolderButtonSettingChanged = Notification.Name("showFolderButtonSettingChanged")
static let autoSaveScreenshotSettingChanged = Notification.Name("autoSaveScreenshotSettingChanged")
static let stashAlwaysOnTopSettingChanged = Notification.Name("stashAlwaysOnTopSettingChanged")
static let shortcutSettingChanged = Notification.Name("shortcutSettingChanged")
static let windowCaptureSettingChanged = Notification.Name("windowCaptureSettingChanged")
static let hideDesktopIconsSettingChanged = Notification.Name("hideDesktopIconsSettingChanged")
static let hideDesktopWidgetsSettingChanged = Notification.Name("hideDesktopWidgetsSettingChanged")
static let stashPreviewSizeChanged = Notification.Name("stashPreviewSizeChanged")
// 🔥💥 HYPERMODE GRID NOTIFICATIONS! 💥🔥
static let stashGridModeChanged = Notification.Name("stashGridModeChanged")
static let stashGridConfigChanged = Notification.Name("stashGridConfigChanged")
// 🔥 NIEUW: Persistent stash notification
static let persistentStashChanged = Notification.Name("persistentStashChanged")
// Add more here if needed for other live updates
}
// NEW: Enum for Screenshot Save Mode
enum ScreenshotSaveMode: Int, CaseIterable, Identifiable {
case automatic = 0
case manual = 1
var id: Int { self.rawValue }
var description: String {
switch self {
case .automatic: return "Always save screenshot to folder"
case .manual: return "Manually decide after screenshot"
}
}
}
// Settings keys
enum SettingsKey {
static let screenshotFolder = "screenshotFolder"
static let thumbnailTimer = "thumbnailTimer"
static let closeAfterDrag = "closeAfterDrag"
static let thumbnailPosition = "thumbnailPosition"
static let showFolderButton = "showFolderButton"
static let closeAfterSave = "closeAfterSave"
static let playSoundOnCapture = "playSoundOnCapture"
static let filenamePrefix = "filenamePrefix"
static let filenameFormatPreset = "filenameFormatPreset"
static let filenameCustomFormat = "filenameCustomFormat"
static let stashWindowBorderWidth = "stashWindowBorderWidth"
static let isRenameActionEnabled = "isRenameActionEnabled"
static let isStashActionEnabled = "isStashActionEnabled"
static let isOCRActionEnabled = "isOCRActionEnabled"
static let isClipboardActionEnabled = "isClipboardActionEnabled"
static let isBackgroundRemoveActionEnabled = "isBackgroundRemoveActionEnabled"
static let isCancelActionEnabled = "isCancelActionEnabled"
static let isRemoveActionEnabled = "isRemoveActionEnabled"
static let isAction3Enabled = "isAction3Enabled"
static let isAction4Enabled = "isAction4Enabled"
static let isDeleteActionEnabled = "isDeleteActionEnabled"
static let isCancelDragActionEnabled = "isCancelDragActionEnabled"
static let startAppOnLogin = "startAppOnLogin"
static let autoSaveScreenshot = "autoSaveScreenshot"
static let saveAfterEdit = "saveAfterEdit"
static let thumbnailDisplayScreen = "thumbnailDisplayScreen"
static let stashAlwaysOnTop = "stashAlwaysOnTop"
static let openOnStartup = "openOnStartup"
static let hasCompletedFirstLaunch = "hasCompletedFirstLaunch"
static let customShortcutModifiers = "customShortcutModifiers"
static let customShortcutKey = "customShortcutKey"
static let useCustomShortcut = "useCustomShortcut"
static let windowCaptureIncludeChildWindows = "windowCaptureIncludeChildWindows"
static let windowCaptureIncludeCursor = "windowCaptureIncludeCursor"
static let windowCaptureHighResolution = "windowCaptureHighResolution"
static let windowCaptureShowSelectionUI = "windowCaptureShowSelectionUI"
static let hideDesktopIconsDuringScreenshot = "hideDesktopIconsDuringScreenshot"
static let hideDesktopWidgetsDuringScreenshot = "hideDesktopWidgetsDuringScreenshot"
static let stashPreviewSize = "stashPreviewSize"
// 🔥💥 HYPERMODE STASH GRID KEYS! 💥🔥
static let stashGridMode = "stashGridMode"
static let stashMaxColumns = "stashMaxColumns"
static let stashMaxRows = "stashMaxRows"
// 🔥 NIEUW: Persistent stash setting
static let persistentStash = "persistentStash"
// 🔄 UPDATE SETTINGS
static let automaticUpdates = "automaticUpdates"
static let includePreReleases = "includePreReleases"
// 🔊 SOUND SETTINGS
static let screenshotSoundVolume = "screenshotSoundVolume"
static let screenshotSoundType = "screenshotSoundType"
// 🗂 CACHE MANAGEMENT SETTINGS
static let cacheRetentionTime = "cacheRetentionTime"
// 🎨 BACKGROUND REMOVAL METHOD PREFERENCE
static let preferredBackgroundRemovalMethod = "preferredBackgroundRemovalMethod"
}
enum ThumbnailPosition: Int, CaseIterable, Codable {
case rightBottom = 0
var description: String {
switch self {
case .rightBottom: return "Bottom Right"
}
}
}
enum ThumbnailDisplayScreen: String, CaseIterable, Codable {
case automatic = "automatic"
case screen1 = "screen1"
case screen2 = "screen2"
case screen3 = "screen3"
case screen4 = "screen4"
case screen5 = "screen5"
var description: String {
switch self {
case .automatic: return "Automatic (where mouse is)"
case .screen1: return "Screen 1"
case .screen2: return "Screen 2"
case .screen3: return "Screen 3"
case .screen4: return "Screen 4"
case .screen5: return "Screen 5"
}
}
func getDisplayName(for screenIndex: Int, screenName: String?) -> String {
switch self {
case .automatic: return "Automatic (where mouse is)"
case .screen1, .screen2, .screen3, .screen4, .screen5:
let screenNumber = screenIndex + 1
if let name = screenName, !name.isEmpty {
return "Screen \(screenNumber) (\(name))"
} else {
return "Screen \(screenNumber)"
}
}
}
}
// NEW: Enum for filename format presets
enum FilenameFormatPreset: Int, CaseIterable, Codable {
case macOSStyle = 0 // Screenshot {YYYY}-{MM}-{DD} at {hh}.{mm}.{ss}
case compactDateTime = 1 // {YYYY}-{MM}-{DD}_{hh}-{mm}-{ss}
case superCompactDateTime = 2 // {YYYYMMDD}_{hhmmss}
case timestamp = 3 // Unix timestamp
case prefixOnly = 4 // Prefix only
case custom = 5 // Custom format
var description: String {
switch self {
case .macOSStyle: return "macOS Style (Screenshot YYYY-MM-DD at hh.mm.ss)"
case .compactDateTime: return "Compact (YYYY-MM-DD_hh-mm-ss)"
case .superCompactDateTime: return "Super Compact (YYYYMMDD_hhmmss)"
case .timestamp: return "Unix Timestamp"
case .prefixOnly: return "Prefix Only"
case .custom: return "Custom..."
}
}
// Placeholder voor custom format string (alleen relevant voor .custom)
// De feitelijke custom string wordt apart opgeslagen.
}
// VOEG DEZE ENUM TOE (ergens bovenaan, of logisch gegroepeerd)
enum ThumbnailFixedSize: String, CaseIterable, Codable {
case small, medium, large, xLarge, xxLarge, xxxLarge
var dimensions: CGSize {
switch self {
case .small: return CGSize(width: 120, height: 90)
case .medium: return CGSize(width: 180, height: 135)
case .large: return CGSize(width: 240, height: 180)
case .xLarge: return CGSize(width: 300, height: 225)
case .xxLarge: return CGSize(width: 360, height: 270)
case .xxxLarge: return CGSize(width: 420, height: 315)
}
}
var displayName: String { // Voor de Picker
switch self {
case .small: return "Small"
case .medium: return "Medium"
case .large: return "Large"
case .xLarge: return "X-Large"
case .xxLarge: return "XX-Large"
case .xxxLarge: return "XXX-Large"
}
}
}
// 🔥💎 MEGA NIEUWE STASH PREVIEW SIZE ENUM! 💎🔥
enum StashPreviewSize: String, CaseIterable, Codable {
case xSmall = "xSmall" // 25% van origineel
case small = "small" // 40% van origineel
case medium = "medium" // 60% van origineel
case large = "large" // 80% van origineel
case xLarge = "xLarge" // 100% van origineel (full size!)
var percentage: CGFloat {
switch self {
case .xSmall: return 0.25
case .small: return 0.40
case .medium: return 0.60
case .large: return 0.80
case .xLarge: return 1.00
}
}
var displayName: String {
switch self {
case .xSmall: return "Extra Small"
case .small: return "Small"
case .medium: return "Medium"
case .large: return "Large"
case .xLarge: return "Extra Large"
}
}
}
// 🔥💥 HYPERMODE STASH GRID MODE ENUM! 💥🔥
enum StashGridMode: String, CaseIterable, Codable, Identifiable {
case fixedColumns = "fixedColumns" // Max kolommen, auto rijen (huidige systeem)
case fixedRows = "fixedRows" // Max rijen, auto kolommen (horizontale strip!)
var id: String { rawValue }
var displayName: String {
switch self {
case .fixedColumns: return "Fixed Columns, Auto Rows"
case .fixedRows: return "Fixed Rows, Auto Columns"
}
}
var description: String {
switch self {
case .fixedColumns: return "Grows vertically with more rows"
case .fixedRows: return "Grows horizontally with more columns"
}
}
var iconName: String {
switch self {
case .fixedColumns: return "rectangle.split.1x3" // Verticale layout (1 kolom, 3 rijen = verticaal groeien)
case .fixedRows: return "rectangle.split.3x1" // Horizontale layout (3 kolommen, 1 rij = horizontaal groeien)
}
}
}
// 🔊 SCREENSHOT SOUND TYPE ENUM
enum ScreenshotSoundType: String, CaseIterable, Codable, Identifiable {
case pop = "Pop"
case glass = "Glass"
case ping = "Ping"
case purr = "Purr"
case tink = "Tink"
case basso = "Basso"
case blow = "Blow"
case bottle = "Bottle"
case frog = "Frog"
case funk = "Funk"
case hero = "Hero"
case morse = "Morse"
case sosumi = "Sosumi"
case submarine = "Submarine"
var id: String { rawValue }
var displayName: String {
switch self {
case .pop: return "Pop"
case .glass: return "Glass"
case .ping: return "Ping"
case .purr: return "Purr"
case .tink: return "Tink"
case .basso: return "Basso"
case .blow: return "Blow"
case .bottle: return "Bottle"
case .frog: return "Frog"
case .funk: return "Funk"
case .hero: return "Hero"
case .morse: return "Morse"
case .sosumi: return "Sosumi"
case .submarine: return "Submarine"
}
}
var systemSoundName: String {
return rawValue
}
}
// 🗂 CACHE RETENTION TIME ENUM
enum CacheRetentionTime: String, CaseIterable, Codable, Identifiable {
case oneHour = "1h"
case sixHours = "6h"
case twelveHours = "12h"
case oneDay = "1d"
case threeDays = "3d"
case oneWeek = "1w"
case twoWeeks = "2w"
case oneMonth = "1m"
case forever = "forever"
var id: String { rawValue }
var displayName: String {
switch self {
case .oneHour: return "1 Hour"
case .sixHours: return "6 Hours"
case .twelveHours: return "12 Hours"
case .oneDay: return "1 Day"
case .threeDays: return "3 Days"
case .oneWeek: return "1 Week"
case .twoWeeks: return "2 Weeks"
case .oneMonth: return "1 Month"
case .forever: return "Forever (Manual delete)"
}
}
var timeInterval: TimeInterval? {
switch self {
case .oneHour: return 3600
case .sixHours: return 3600 * 6
case .twelveHours: return 3600 * 12
case .oneDay: return 86400
case .threeDays: return 86400 * 3
case .oneWeek: return 86400 * 7
case .twoWeeks: return 86400 * 14
case .oneMonth: return 86400 * 30
case .forever: return nil // Never delete
}
}
}
// Add after the existing SettingsKey enum
enum ActionType: String, CaseIterable, Identifiable {
case rename = "Rename"
case stash = "Stash"
case ocr = "OCR"
case clipboard = "Clipboard"
case backgroundRemove = "BackgroundRemove"
case cancel = "Cancel"
case remove = "Remove"
var id: String { self.rawValue }
var settingsKey: String {
switch self {
case .rename: return SettingsKey.isRenameActionEnabled
case .stash: return SettingsKey.isStashActionEnabled
case .ocr: return SettingsKey.isOCRActionEnabled
case .clipboard: return SettingsKey.isClipboardActionEnabled
case .backgroundRemove: return SettingsKey.isBackgroundRemoveActionEnabled
case .cancel: return SettingsKey.isCancelActionEnabled
case .remove: return SettingsKey.isRemoveActionEnabled
}
}
var displayName: String {
switch self {
case .rename: return "Rename"
case .stash: return "Stash"
case .ocr: return "Text Extract"
case .clipboard: return "Clipboard"
case .backgroundRemove: return "Remove Background"
case .cancel: return "Cancel"
case .remove: return "Remove"
}
}
}
// MARK: - Background Removal Method Preference
enum BackgroundRemovalMethod: String, CaseIterable, Identifiable {
case auto = "auto"
case rmbg = "rmbg"
case vision = "vision"
var id: String { self.rawValue }
var displayName: String {
switch self {
case .auto: return "Auto (RMBG → Vision fallback)"
case .rmbg: return "RMBG-1.4 only"
case .vision: return "Vision Framework only"
}
}
var description: String {
switch self {
case .auto: return "Tries RMBG-1.4 first, falls back to Vision if unavailable"
case .rmbg: return "Uses only RMBG-1.4 model (requires download)"
case .vision: return "Uses only Apple's Vision Framework (always available)"
}
}
}