Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions Sources/Deckle/AppState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,67 @@ final class AppState: ObservableObject {
didSet { defaults.set(grainStrength, forKey: Keys.grainStrength) }
}

// MARK: Favorites & Desk Lamp

/// Pinned favorite texture IDs for quick-access switching bar.
@Published var favoriteTextureIDs: [String] {
didSet { defaults.set(favoriteTextureIDs, forKey: Keys.favoriteTextureIDs) }
}

/// Whether Desk Lamp mode (warm ambient light pool over texture) is enabled.
@Published var enableDeskLamp: Bool {
didSet { defaults.set(enableDeskLamp, forKey: Keys.deskLamp) }
}

/// Color temperature/warmth of Desk Lamp (0.0 = cool/neutral, 1.0 = deep amber).
@Published var deskLampWarmth: Double {
didSet { defaults.set(deskLampWarmth, forKey: Keys.deskLampWarmth) }
}

/// Brightness/intensity of Desk Lamp pool (0.05 ... 0.50).
@Published var deskLampBrightness: Double {
didSet { defaults.set(deskLampBrightness, forKey: Keys.deskLampBrightness) }
}

/// Spread/radius of Desk Lamp light pool (0.3 ... 1.2).
@Published var deskLampSpread: Double {
didSet { defaults.set(deskLampSpread, forKey: Keys.deskLampSpread) }
}

enum LampPosition: String, CaseIterable, Identifiable {
case topRight = "Top Right"
case topLeft = "Top Left"
case topCenter = "Top Center"
case center = "Center"

var id: String { rawValue }

var point: CGPoint {
switch self {
case .topRight: return CGPoint(x: 0.85, y: 0.15)
case .topLeft: return CGPoint(x: 0.15, y: 0.15)
case .topCenter: return CGPoint(x: 0.50, y: 0.10)
case .center: return CGPoint(x: 0.50, y: 0.50)
}
}
}

@Published var deskLampPosition: LampPosition {
didSet { defaults.set(deskLampPosition.rawValue, forKey: Keys.deskLampPosition) }
}

func isFavorite(_ id: String) -> Bool {
favoriteTextureIDs.contains(id)
}

func toggleFavorite(_ id: String) {
if isFavorite(id) {
favoriteTextureIDs.removeAll { $0 == id }
} else if favoriteTextureIDs.count < 6 {
favoriteTextureIDs.append(id)
}
}

var grainAdjustments: TextureRenderer.GrainAdjustments {
.init(scale: grainScale, strength: grainStrength)
}
Expand Down Expand Up @@ -138,6 +199,12 @@ final class AppState: ObservableObject {
static let appRuleMode = "appRuleMode"
static let ruleApps = "ruleApps"
static let customPapers = "customPapers"
static let favoriteTextureIDs = "favoriteTextureIDs"
static let deskLamp = "enableDeskLamp"
static let deskLampWarmth = "deskLampWarmth"
static let deskLampBrightness = "deskLampBrightness"
static let deskLampSpread = "deskLampSpread"
static let deskLampPosition = "deskLampPosition"
}

private let defaults = UserDefaults.standard
Expand All @@ -156,6 +223,13 @@ final class AppState: ObservableObject {
.flatMap { try? JSONDecoder().decode([RuleApp].self, from: $0) } ?? []
customPapers = defaults.data(forKey: Keys.customPapers)
.flatMap { try? JSONDecoder().decode([CustomPaper].self, from: $0) } ?? []
favoriteTextureIDs = defaults.stringArray(forKey: Keys.favoriteTextureIDs)
?? ["classic-matte", "sunbaked-parchment", "whisper-weave", "carbon-ledger"]
enableDeskLamp = defaults.bool(forKey: Keys.deskLamp)
deskLampWarmth = defaults.object(forKey: Keys.deskLampWarmth) as? Double ?? 0.6
deskLampBrightness = defaults.object(forKey: Keys.deskLampBrightness) as? Double ?? 0.25
deskLampSpread = defaults.object(forKey: Keys.deskLampSpread) as? Double ?? 0.75
deskLampPosition = LampPosition(rawValue: defaults.string(forKey: Keys.deskLampPosition) ?? "") ?? .topRight
}

private func scheduleSnoozeExpiry() {
Expand Down
Loading