|
@@ -23,6 +23,7 @@ struct LauncherRootView: View {
|
|
|
@State private var showingPremiumScreen = false
|
|
@State private var showingPremiumScreen = false
|
|
|
@State private var showingCreateAppSheet = false
|
|
@State private var showingCreateAppSheet = false
|
|
|
@State private var previouslyPremiumUnlocked = false
|
|
@State private var previouslyPremiumUnlocked = false
|
|
|
|
|
+ @State private var lastKnownPremiumProductID: PremiumProductID?
|
|
|
@State private var ratingPromptTask: Task<Void, Never>?
|
|
@State private var ratingPromptTask: Task<Void, Never>?
|
|
|
@State private var customApps: [LauncherApp] = []
|
|
@State private var customApps: [LauncherApp] = []
|
|
|
@State private var appOrder: [UUID] = []
|
|
@State private var appOrder: [UUID] = []
|
|
@@ -154,7 +155,7 @@ struct LauncherRootView: View {
|
|
|
|
|
|
|
|
PromoBanner(
|
|
PromoBanner(
|
|
|
isPremiumUnlocked: premiumStore.isPremiumUnlocked,
|
|
isPremiumUnlocked: premiumStore.isPremiumUnlocked,
|
|
|
- activePremiumProductID: premiumStore.activePremiumProductID,
|
|
|
|
|
|
|
+ activePremiumProductID: premiumStore.activePremiumProductID ?? lastKnownPremiumProductID,
|
|
|
onCloseTap: {
|
|
onCloseTap: {
|
|
|
if !premiumStore.isPremiumUnlocked {
|
|
if !premiumStore.isPremiumUnlocked {
|
|
|
showingPremiumScreen = true
|
|
showingPremiumScreen = true
|
|
@@ -203,8 +204,16 @@ struct LauncherRootView: View {
|
|
|
}
|
|
}
|
|
|
previouslyPremiumUnlocked = unlocked
|
|
previouslyPremiumUnlocked = unlocked
|
|
|
}
|
|
}
|
|
|
|
|
+ .onChange(of: premiumStore.activePremiumProductID) { newValue in
|
|
|
|
|
+ if let newValue {
|
|
|
|
|
+ lastKnownPremiumProductID = newValue
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
.onAppear {
|
|
.onAppear {
|
|
|
previouslyPremiumUnlocked = premiumStore.isPremiumUnlocked
|
|
previouslyPremiumUnlocked = premiumStore.isPremiumUnlocked
|
|
|
|
|
+ if let active = premiumStore.activePremiumProductID {
|
|
|
|
|
+ lastKnownPremiumProductID = active
|
|
|
|
|
+ }
|
|
|
loadCustomAppsFromStorage()
|
|
loadCustomAppsFromStorage()
|
|
|
loadAppOrderFromStorage()
|
|
loadAppOrderFromStorage()
|
|
|
normalizeAppOrderAndPersist()
|
|
normalizeAppOrderAndPersist()
|
|
@@ -1292,48 +1301,31 @@ private struct PromoBanner: View {
|
|
|
|
|
|
|
|
Spacer()
|
|
Spacer()
|
|
|
|
|
|
|
|
- HStack(spacing: 8) {
|
|
|
|
|
- if isPremiumUnlocked && activePremiumProductID == .yearly {
|
|
|
|
|
- Button(action: onUpgradeTap) {
|
|
|
|
|
- Text("Upgrade Plan")
|
|
|
|
|
- .font(.system(size: 13, weight: .semibold))
|
|
|
|
|
- .foregroundStyle(.white)
|
|
|
|
|
- .padding(.horizontal, 12)
|
|
|
|
|
- .padding(.vertical, 6)
|
|
|
|
|
- .background(
|
|
|
|
|
- Capsule(style: .continuous)
|
|
|
|
|
- .fill(Color(red: 1.0, green: 0.67, blue: 0.2).opacity(0.95))
|
|
|
|
|
- )
|
|
|
|
|
- }
|
|
|
|
|
- .buttonStyle(.plain)
|
|
|
|
|
-
|
|
|
|
|
- Button(action: onManageSubscriptionTap) {
|
|
|
|
|
- Text("Manage Subscription")
|
|
|
|
|
- .font(.system(size: 13, weight: .semibold))
|
|
|
|
|
- .foregroundStyle(.white)
|
|
|
|
|
- .padding(.horizontal, 12)
|
|
|
|
|
- .padding(.vertical, 6)
|
|
|
|
|
- .background(
|
|
|
|
|
- Capsule(style: .continuous)
|
|
|
|
|
- .fill(Color.blue.opacity(0.92))
|
|
|
|
|
- )
|
|
|
|
|
- }
|
|
|
|
|
- .buttonStyle(.plain)
|
|
|
|
|
- } else {
|
|
|
|
|
- Button(action: isPremiumUnlocked ? onManageSubscriptionTap : onUpgradeTap) {
|
|
|
|
|
- Text(isPremiumUnlocked ? "Manage Subscription" : "Upgrade")
|
|
|
|
|
|
|
+ let isPremium = isPremiumUnlocked
|
|
|
|
|
+ // `activePremiumProductID` can be temporarily nil during entitlement refresh.
|
|
|
|
|
+ // Treat "Premium + not yearly" as Lifetime for routing to subscriptions.
|
|
|
|
|
+ let isLifetime = isPremium && activePremiumProductID != .yearly
|
|
|
|
|
+ let showsManageLabel = isPremium
|
|
|
|
|
+ Button(action: isLifetime ? onManageSubscriptionTap : onUpgradeTap) {
|
|
|
|
|
+ HStack(spacing: 7) {
|
|
|
|
|
+ if showsManageLabel {
|
|
|
|
|
+ Image(systemName: "crown.fill")
|
|
|
.font(.system(size: 13, weight: .semibold))
|
|
.font(.system(size: 13, weight: .semibold))
|
|
|
- .foregroundStyle(.white)
|
|
|
|
|
- .padding(.horizontal, 12)
|
|
|
|
|
- .padding(.vertical, 6)
|
|
|
|
|
- .background(
|
|
|
|
|
- Capsule(style: .continuous)
|
|
|
|
|
- .fill(Color.blue.opacity(0.92))
|
|
|
|
|
- )
|
|
|
|
|
}
|
|
}
|
|
|
- .buttonStyle(.plain)
|
|
|
|
|
|
|
+ Text(showsManageLabel ? "Manage Subscription" : "Upgrade")
|
|
|
|
|
+ .font(.system(size: 13, weight: .semibold))
|
|
|
}
|
|
}
|
|
|
|
|
+ .foregroundStyle(.white)
|
|
|
|
|
+ .padding(.horizontal, 12)
|
|
|
|
|
+ .padding(.vertical, 6)
|
|
|
|
|
+ .background(
|
|
|
|
|
+ Capsule(style: .continuous)
|
|
|
|
|
+ .fill(showsManageLabel
|
|
|
|
|
+ ? Color(red: 1.0, green: 0.67, blue: 0.2).opacity(0.95)
|
|
|
|
|
+ : Color.blue.opacity(0.92))
|
|
|
|
|
+ )
|
|
|
}
|
|
}
|
|
|
|
|
+ .buttonStyle(.plain)
|
|
|
}
|
|
}
|
|
|
.padding(.horizontal, 11)
|
|
.padding(.horizontal, 11)
|
|
|
.padding(.vertical, 8)
|
|
.padding(.vertical, 8)
|