From cf4a1ad4dbc8f4a3f61a0a1a32f63d31c3562b27 Mon Sep 17 00:00:00 2001
From: Ariver <shanghai3168@gmail.com>
Date: Thu, 02 Jul 2026 03:07:40 +0800
Subject: [PATCH] Record TagLauncher 8.3.2 release freeze
---
src/Apptag/ProEntitlement.swift | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 54 insertions(+), 2 deletions(-)
diff --git a/src/Apptag/ProEntitlement.swift b/src/Apptag/ProEntitlement.swift
index 1674af4..4d5fc2b 100644
--- a/src/Apptag/ProEntitlement.swift
+++ b/src/Apptag/ProEntitlement.swift
@@ -7,6 +7,7 @@
case layoutImport
case layoutExport
case customTagColors
+ case customContainerQuota
case unlimitedNotes
case persistentAppSorting
case customHotkeys
@@ -21,6 +22,8 @@
return "pro.feature.export"
case .customTagColors:
return "pro.feature.customTagColors"
+ case .customContainerQuota:
+ return "pro.feature.customContainerQuota"
case .unlimitedNotes:
return "pro.feature.notes"
case .persistentAppSorting:
@@ -40,6 +43,8 @@
return "pro.feature.export.benefit"
case .customTagColors:
return "pro.feature.customTagColors.benefit"
+ case .customContainerQuota:
+ return "pro.feature.customContainerQuota.benefit"
case .unlimitedNotes:
return "pro.feature.notes.benefit"
case .persistentAppSorting:
@@ -139,14 +144,30 @@
case blocked(ProNoteQuotaStatus)
}
+struct ProCustomContainerQuotaStatus: Equatable {
+ let isUnlimited: Bool
+ let used: Int
+ let limit: Int
+
+ var remaining: Int {
+ max(0, limit - used)
+ }
+}
+
+enum ProCustomContainerMaintenanceDecision: Equatable {
+ case allow(ProCustomContainerQuotaStatus)
+ case blocked(ProCustomContainerQuotaStatus)
+}
+
enum ProEntitlementConfig {
// 发布前只改这里,不允许把商品信息和边界版本散落到业务模块。
static let lifetimeProductID = "com.taglauncher.pro.lifetime"
- static let firstFreeProVersion = "8.1.0"
+ static let firstFreeProVersion = "8.3.2"
static let legacyFallbackOriginalPurchaseDateISO8601: String? = nil
static let freeThemes: Set<AppGridTheme> = [.defaultLight, .black]
static let freeNoteLimit = 3
+ static let freeCustomContainerLimit = 6
static let defaultThemePreviewDuration: TimeInterval = 5 * 60
static let qaStateEnvKey = "TAGLAUNCHER_QA_PRO_STATE"
@@ -225,7 +246,7 @@
static func isUnlocked(_ feature: ProFeature) -> Bool {
switch feature {
- case .premiumThemes, .layoutImport, .layoutExport, .customTagColors, .unlimitedNotes, .persistentAppSorting, .customHotkeys:
+ case .premiumThemes, .layoutImport, .layoutExport, .customTagColors, .customContainerQuota, .unlimitedNotes, .persistentAppSorting, .customHotkeys:
return accessState().isUnlocked
}
}
@@ -344,6 +365,37 @@
throw ProEntitlementError.noteQuotaExceeded(status)
}
}
+
+ static func customContainerQuotaStatus(in store: TagDatabase.Store? = nil) -> ProCustomContainerQuotaStatus {
+ guard !isUnlocked(.customContainerQuota) else {
+ return ProCustomContainerQuotaStatus(isUnlimited: true, used: 0, limit: Int.max)
+ }
+ let used = TagDatabase.customMaintainedContainerCount(in: store)
+ return ProCustomContainerQuotaStatus(
+ isUnlimited: false,
+ used: used,
+ limit: ProEntitlementConfig.freeCustomContainerLimit
+ )
+ }
+
+ static func customContainerMaintenanceDecision(
+ addingCustomContainerCount addedCount: Int,
+ in store: TagDatabase.Store? = nil
+ ) -> ProCustomContainerMaintenanceDecision {
+ let status = customContainerQuotaStatus(in: store)
+ guard !status.isUnlimited else { return .allow(status) }
+ guard addedCount > 0 else { return .allow(status) }
+ guard status.used + addedCount <= status.limit else {
+ return .blocked(status)
+ }
+ return .allow(
+ ProCustomContainerQuotaStatus(
+ isUnlimited: false,
+ used: status.used + addedCount,
+ limit: status.limit
+ )
+ )
+ }
}
@MainActor
--
Gitblit v1.9.3