Ariver
2026-06-28 755ca63e4d37c1a54db7fc6475152319a4e46ceb
src/Apptag/ProEntitlement.swift
@@ -95,6 +95,7 @@
struct ProThemePreviewState: Equatable {
    let theme: AppGridTheme
    let themeTuning: Double?
    let startedAt: Date
    let endsAt: Date
@@ -124,7 +125,7 @@
    static let firstFreeProVersion = "8.1.0"
    static let legacyFallbackOriginalPurchaseDateISO8601: String? = nil
    static let freeThemes: Set<AppGridTheme> = [.defaultLight, .deepBlue, .black]
    static let freeThemes: Set<AppGridTheme> = [.defaultLight, .black]
    static let freeNoteLimit = 5
    static let defaultThemePreviewDuration: TimeInterval = 5 * 60
@@ -163,6 +164,7 @@
private struct ProEntitlementSnapshot {
    var accessState: ProAccessState = .free
    var previewThemeID: String? = nil
    var previewThemeTuning: Double? = nil
}
private enum ProEntitlementSnapshotStore {
@@ -218,6 +220,19 @@
            return .defaultLight
        }
        return storedTheme
    }
    static func effectiveThemeTuning(for storedTheme: AppGridTheme, storedTuning: Double?) -> Double? {
        let snapshot = ProEntitlementSnapshotStore.read()
        if let previewID = snapshot.previewThemeID,
           let previewTheme = AppGridTheme(rawValue: previewID),
           previewTheme.supportsColorTuning {
            return previewTheme.normalizedTuning(snapshot.previewThemeTuning)
        }
        guard canUseTheme(storedTheme), storedTheme.supportsColorTuning else {
            return nil
        }
        return storedTheme.normalizedTuning(storedTuning)
    }
    static func noteQuotaStatus(in store: TagDatabase.Store? = nil) -> ProNoteQuotaStatus {
@@ -401,7 +416,7 @@
        }
    }
    func startThemePreview(for theme: AppGridTheme) {
    func startThemePreview(for theme: AppGridTheme, tuning: Double? = nil) {
        guard !ProEntitlementConfig.freeThemes.contains(theme) else { return }
        guard !accessState.isUnlocked else { return }
@@ -409,6 +424,7 @@
        let preview = ProThemePreviewState(
            theme: theme,
            themeTuning: theme.supportsColorTuning ? theme.normalizedTuning(tuning) : nil,
            startedAt: Date(),
            endsAt: Date().addingTimeInterval(ProEntitlementConfig.themePreviewDuration)
        )
@@ -420,6 +436,21 @@
            guard !Task.isCancelled else { return }
            self?.stopThemePreview()
        }
    }
    func updateThemePreviewTuning(_ tuning: Double, for theme: AppGridTheme) {
        guard let preview = themePreviewState,
              preview.theme == theme,
              theme.supportsColorTuning,
              !accessState.isUnlocked
        else { return }
        let updatedPreview = ProThemePreviewState(
            theme: preview.theme,
            themeTuning: theme.normalizedTuning(tuning),
            startedAt: preview.startedAt,
            endsAt: preview.endsAt
        )
        applyThemePreview(updatedPreview)
    }
    func stopThemePreview() {
@@ -559,6 +590,7 @@
        themePreviewState = preview
        ProEntitlementSnapshotStore.update { snapshot in
            snapshot.previewThemeID = preview?.theme.rawValue
            snapshot.previewThemeTuning = preview?.themeTuning
        }
    }