From 71a520840eb3debe46173c1f73bc85bbea0b1aa6 Mon Sep 17 00:00:00 2001
From: Ariver <shanghai3168@gmail.com>
Date: Sun, 28 Jun 2026 23:42:38 +0800
Subject: [PATCH] Implement Pro custom hotkeys for 8.2.0
---
src/Apptag/ProEntitlement.swift | 48 +++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 45 insertions(+), 3 deletions(-)
diff --git a/src/Apptag/ProEntitlement.swift b/src/Apptag/ProEntitlement.swift
index 4841e55..3267c3e 100644
--- a/src/Apptag/ProEntitlement.swift
+++ b/src/Apptag/ProEntitlement.swift
@@ -8,6 +8,7 @@
case layoutExport
case unlimitedNotes
case persistentAppSorting
+ case customHotkeys
var titleKey: String {
switch self {
@@ -21,6 +22,8 @@
return "pro.feature.notes"
case .persistentAppSorting:
return "pro.feature.sorting"
+ case .customHotkeys:
+ return "pro.feature.customHotkeys"
}
}
@@ -36,6 +39,8 @@
return "pro.feature.notes.benefit"
case .persistentAppSorting:
return "pro.feature.sorting.benefit"
+ case .customHotkeys:
+ return "pro.feature.customHotkeys.benefit"
}
}
}
@@ -95,6 +100,7 @@
struct ProThemePreviewState: Equatable {
let theme: AppGridTheme
+ let themeTuning: Double?
let startedAt: Date
let endsAt: Date
@@ -124,7 +130,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 +169,7 @@
private struct ProEntitlementSnapshot {
var accessState: ProAccessState = .free
var previewThemeID: String? = nil
+ var previewThemeTuning: Double? = nil
}
private enum ProEntitlementSnapshotStore {
@@ -200,7 +207,7 @@
static func isUnlocked(_ feature: ProFeature) -> Bool {
switch feature {
- case .premiumThemes, .layoutImport, .layoutExport, .unlimitedNotes, .persistentAppSorting:
+ case .premiumThemes, .layoutImport, .layoutExport, .unlimitedNotes, .persistentAppSorting, .customHotkeys:
return accessState().isUnlocked
}
}
@@ -218,6 +225,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 +421,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 +429,7 @@
let preview = ProThemePreviewState(
theme: theme,
+ themeTuning: theme.supportsColorTuning ? theme.normalizedTuning(tuning) : nil,
startedAt: Date(),
endsAt: Date().addingTimeInterval(ProEntitlementConfig.themePreviewDuration)
)
@@ -420,6 +441,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() {
@@ -538,9 +574,14 @@
originalAppVersion: String? = nil,
originalPurchaseDate: Date? = nil
) {
+ let previousState = accessState
accessState = state
ProEntitlementSnapshotStore.update { snapshot in
snapshot.accessState = state
+ }
+
+ if previousState != state {
+ NotificationCenter.default.post(name: .tagLauncherProEntitlementChanged, object: nil)
}
if persistCache {
@@ -559,6 +600,7 @@
themePreviewState = preview
ProEntitlementSnapshotStore.update { snapshot in
snapshot.previewThemeID = preview?.theme.rawValue
+ snapshot.previewThemeTuning = preview?.themeTuning
}
}
--
Gitblit v1.9.3