Skip to content

Commit 858e2de

Browse files
author
Carlos Cabanero
committed
New Paywall and Entitlements structure
- Intro Offers as part of Subscriptions so we can improve the structure there. - Got rid of old flows with Notifications for Subscription updates. - New Paywall - Blink Plus only. - Blink Classic now has all Blink Plus features.
1 parent bf7793e commit 858e2de

36 files changed

+1841
-2138
lines changed

Blink.xcodeproj/project.pbxproj

Lines changed: 27 additions & 26 deletions
Large diffs are not rendered by default.

Blink/Intro.swift

Lines changed: 0 additions & 1122 deletions
This file was deleted.

Blink/SceneDelegate.swift

Lines changed: 127 additions & 166 deletions
Large diffs are not rendered by default.

Blink/Snippets/SnippetEditingView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ class TextViewBuilder {
8282

8383
public final class PragmataProTheme<T: Runestone.Theme>: Runestone.Theme {
8484

85-
public var font = BlinkFonts.snippetEditContent
85+
public var font = BlinkSnippetsFonts.snippetEditContent
8686

8787
public var textColor: UIColor {
8888
originalTheme.textColor

Blink/Snippets/SnippetView.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,14 @@ public struct SnippetView: View {
4747
} label: {
4848
VStack(alignment: .leading) {
4949
HStack {
50-
Text(index).font(Font(BlinkFonts.snippetEditContent)).bold(fuzzyMode)
50+
Text(index).font(Font(BlinkSnippetsFonts.snippetEditContent)).bold(fuzzyMode)
5151
.frame(maxWidth: .infinity, alignment: .leading).opacity(fuzzyMode ? 1.0 : 0.4)
5252
if selected {
5353
Spacer()
5454
Text(Image(systemName: "return")).opacity(0.5)
5555
}
5656
}
57-
Text(content).font(Font(BlinkFonts.snippetEditContent))
57+
Text(content).font(Font(BlinkSnippetsFonts.snippetEditContent))
5858
.frame(maxWidth: .infinity, alignment: .leading)
5959
.opacity(fuzzyMode ? 0.4 : 1.0)
6060
}

Blink/Snippets/SnippetsListView.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@ import Foundation
3333
import SwiftUI
3434
import BlinkSnippets
3535

36+
public enum BlinkSnippetsFonts {
37+
// static let snippetIndex = Font.custom(BLINK_APP_FONT_NAME, size: 18, relativeTo: .body)
38+
// static let snippetContent = Font.custom(BLINK_APP_FONT_NAME, size: 18, relativeTo: .body)
39+
static let snippetEditContent = UIFont(name: BLINK_APP_FONT_NAME, size: 18)!
40+
}
41+
3642
public struct SnippetsListView: View {
3743
@ObservedObject var model: SearchModel
3844

Blink/SpaceController.swift

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -936,24 +936,21 @@ extension SpaceController {
936936
}
937937
}
938938

939-
@objc func showWalkthroughAction() {
940-
if self.view.window == ShadowWindow.shared {
941-
return
942-
}
943-
DispatchQueue.main.async {
944-
_ = KBTracker.shared.input?.resignFirstResponder()
945-
let ctrl = UIHostingController(rootView: WalkthroughView(urlHandler: blink_openurl,
946-
dismissHandler: { self.dismiss(animated: true) })
947-
)
948-
ctrl.modalPresentationStyle = .formSheet
949-
self.present(ctrl, animated: false)
950-
}
951-
}
939+
// @objc func showWalkthroughAction() {
940+
// if self.view.window == ShadowWindow.shared {
941+
// return
942+
// }
943+
// DispatchQueue.main.async {
944+
// _ = KBTracker.shared.input?.resignFirstResponder()
945+
// let ctrl = UIHostingController(rootView: WalkthroughView(urlHandler: blink_openurl,
946+
// dismissHandler: { self.dismiss(animated: true) })
947+
// )
948+
// ctrl.modalPresentationStyle = .formSheet
949+
// self.present(ctrl, animated: false)
950+
// }
951+
// }
952952

953953
@objc func showSnippetsAction() {
954-
guard EntitlementsManager.shared.earlyAccessFeatures.active || FeatureFlags.earlyAccessFeatures else {
955-
return
956-
}
957954
if let _ = _snippetsVC {
958955
return
959956
}
@@ -976,11 +973,7 @@ extension SpaceController {
976973
self.view.addSubview(menu.tapToCloseView)
977974

978975
var ids: [BlinkActionID] = []
979-
if EntitlementsManager.shared.earlyAccessFeatures.active || FeatureFlags.earlyAccessFeatures {
980-
ids.append(contentsOf: [.snippets])
981-
}
982-
983-
ids.append(contentsOf: [.tabClose, .tabCreate])
976+
ids.append(contentsOf: [.snippets, .tabClose, .tabCreate])
984977

985978
if DeviceInfo.shared().hasCorners {
986979
ids.append(contentsOf: [.layoutMenu])

Blink/Subscriptions/EntitlementsManager.swift

Lines changed: 20 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -43,23 +43,17 @@ let ProductBlinkShellClassicID = "blink_shell_classic_unlimited_0"
4343
let ProductBlinkBuildBasicID = "blink_build_basic_1m_799"
4444
let ProductBlinkPlusBuildBasicID = "blink_plus_build_1m_999"
4545

46-
47-
private let NagTimestamp = "NagTimestamp"
48-
extension Notification.Name {
49-
public static let subscriptionNag = Notification.Name("SubscriptionNag")
50-
}
51-
5246
// Decoupled from RevCat Entitlement
5347
public struct Entitlement: Identifiable, Equatable, Hashable {
5448
public let id: String
5549
public var active: Bool
5650
public var unlockProductID: String?
5751
public var period: EntitlementPeriodType
58-
52+
5953
public static var inactiveUnlimitedScreenTime = Self(id: UnlimitedScreenTimeEntitlementID, active: false, unlockProductID: nil, period: .None)
60-
54+
6155
public static var earlyAccessFeatures = Self(id: EarlyAccessFeaturesEntitlementID, active: false, unlockProductID: nil, period: .None)
62-
56+
6357
public static var build = Self(id: BuildEntitlementID, active: false, unlockProductID: nil, period: .None)
6458
}
6559

@@ -78,106 +72,55 @@ public protocol EntitlementsSource: AnyObject {
7872
}
7973

8074
public class EntitlementsManager: ObservableObject, EntitlementsSourceDelegate {
81-
75+
8276
public static let shared = EntitlementsManager([AppStoreEntitlementsSource()])
83-
77+
8478
@Published var unlimitedTimeAccess: Entitlement = .inactiveUnlimitedScreenTime
8579
@Published var earlyAccessFeatures: Entitlement = .earlyAccessFeatures
8680
@Published var build: Entitlement = .build
87-
81+
8882
@Published var activeSubscriptions: Set<String> = .init()
8983
@Published var nonSubscriptionTransactions: Set<String> = .init()
90-
@Published var isUnknownState: Bool = true
91-
92-
public var navigationCtrl: UINavigationController? = nil
93-
@Published var navigationSteps: [EarlyFeatureAccessSteps] = []
9484

9585
private let _sources: [EntitlementsSource]
96-
86+
9787
private init(_ sources: [EntitlementsSource]) {
9888
_sources = sources
9989
for s in sources {
10090
s.delegate = self
10191
}
10292
}
103-
93+
10494
public func startUpdates() {
10595
for s in _sources {
10696
s.startUpdates()
10797
}
10898
}
109-
99+
110100
public func didUpdateEntitlements(
111101
source: EntitlementsSource,
112102
entitlements: Dictionary<String, Entitlement>,
113103
activeSubscriptions: Set<String>,
114104
nonSubscriptionTransactions: Set<String>
115105
) {
116-
117-
defer {
118-
self.isUnknownState = false
119-
}
120-
121106
// TODO: merge stategy from multiple sources
122107
self.activeSubscriptions = activeSubscriptions
123108
self.nonSubscriptionTransactions = nonSubscriptionTransactions
124-
109+
125110
let oldValue = self.unlimitedTimeAccess;
126111
if let newValue = entitlements[UnlimitedScreenTimeEntitlementID] {
127112
self.unlimitedTimeAccess = newValue
128113
}
129-
114+
130115
if let newValue = entitlements[EarlyAccessFeaturesEntitlementID] {
131116
self.earlyAccessFeatures = newValue
132117
}
133-
118+
134119
if let newValue = entitlements[BuildEntitlementID] {
135120
self.build = newValue
136121
}
137-
138-
if isUnknownState {
139-
_updateSubscriptionNag()
140-
} else {
141-
if oldValue.active != self.unlimitedTimeAccess.active {
142-
_updateSubscriptionNag()
143-
}
144-
}
145-
146-
}
147-
148-
private func _updateSubscriptionNag() {
149-
showPaywall()
150122
}
151-
152-
@Published var keepShowingPaywall: Bool = false
153-
@Published var shouldDismissPaywall: Bool = false
154-
155-
func showPaywall(force: Bool = false) {
156-
keepShowingPaywall = force
157-
NotificationCenter.default.post(name: .subscriptionNag, object: nil)
158-
}
159-
160-
func doShowPaywall() -> Bool {
161-
if keepShowingPaywall {
162-
return true
163-
}
164-
if shouldDismissPaywall {
165-
return false
166-
}
167-
168-
if ProcessInfo().isMacCatalystApp {
169-
return false
170-
}
171-
return !(self.unlimitedTimeAccess.active || FeatureFlags.earlyAccessFeatures)
172-
}
173-
174-
func dismissPaywall() {
175-
keepShowingPaywall = false
176-
shouldDismissPaywall = true
177-
NotificationCenter.default.post(name: .subscriptionNag, object: nil)
178-
shouldDismissPaywall = false
179-
}
180-
123+
181124
public func currentPlanName() -> String {
182125
if FeatureFlags.earlyAccessFeatures {
183126
return "TestFlight Plan"
@@ -196,7 +139,7 @@ public class EntitlementsManager: ObservableObject, EntitlementsSourceDelegate {
196139
}
197140
return "Free Plan"
198141
}
199-
142+
200143
public func customerTier() -> CustomerTier {
201144
if activeSubscriptions.contains(ProductBlinkShellPlusID) || activeSubscriptions.contains(ProductBlinkPlusID){
202145
return CustomerTier.Plus
@@ -207,9 +150,14 @@ public class EntitlementsManager: ObservableObject, EntitlementsSourceDelegate {
207150
if PublishingOptions.current == .testFlight {
208151
return CustomerTier.TestFlight
209152
}
210-
153+
211154
return CustomerTier.Free
212155
}
156+
157+
public func hasActiveSubscriptions() -> Bool {
158+
print(currentPlanName())
159+
return customerTier() != CustomerTier.Free
160+
}
213161
}
214162

215163
public enum CustomerTier {

0 commit comments

Comments
 (0)