| | |
| | | |
| | | struct ProThemePreviewState: Equatable { |
| | | let theme: AppGridTheme |
| | | let themeTuning: Double? |
| | | let startedAt: Date |
| | | let endsAt: Date |
| | | |
| | |
| | | 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 |
| | | |
| | |
| | | private struct ProEntitlementSnapshot { |
| | | var accessState: ProAccessState = .free |
| | | var previewThemeID: String? = nil |
| | | var previewThemeTuning: Double? = nil |
| | | } |
| | | |
| | | private enum ProEntitlementSnapshotStore { |
| | |
| | | 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 { |
| | |
| | | } |
| | | } |
| | | |
| | | 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 } |
| | | |
| | |
| | | |
| | | let preview = ProThemePreviewState( |
| | | theme: theme, |
| | | themeTuning: theme.supportsColorTuning ? theme.normalizedTuning(tuning) : nil, |
| | | startedAt: Date(), |
| | | endsAt: Date().addingTimeInterval(ProEntitlementConfig.themePreviewDuration) |
| | | ) |
| | |
| | | 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() { |
| | |
| | | themePreviewState = preview |
| | | ProEntitlementSnapshotStore.update { snapshot in |
| | | snapshot.previewThemeID = preview?.theme.rawValue |
| | | snapshot.previewThemeTuning = preview?.themeTuning |
| | | } |
| | | } |
| | | |