@@ -17,8 +17,14 @@ class VaultListViewController: ListViewController<VaultCellViewModel> {
17
17
weak var coordinator : MainCoordinator ?
18
18
19
19
private let viewModel : VaultListViewModelProtocol
20
- private var observer : NSObjectProtocol ?
20
+ private var willEnterForegroundObserver : NSObjectProtocol ?
21
21
@Dependency ( \. fullVersionChecker) private var fullVersionChecker
22
+ @Dependency ( \. cryptomatorSettings) private var cryptomatorSettings
23
+
24
+ #if !ALWAYS_PREMIUM
25
+ private var bannerView : UIView ?
26
+ private var fullVersionPurchasedObserver : NSObjectProtocol ?
27
+ #endif
22
28
23
29
init ( with viewModel: VaultListViewModelProtocol ) {
24
30
self . viewModel = viewModel
@@ -44,11 +50,18 @@ class VaultListViewController: ListViewController<VaultCellViewModel> {
44
50
let addNewVaulButton = UIBarButtonItem ( barButtonSystemItem: . add, target: self , action: #selector( addNewVault) )
45
51
navigationItem. rightBarButtonItem = addNewVaulButton
46
52
47
- observer = NotificationCenter . default. addObserver ( forName: UIApplication . willEnterForegroundNotification, object: nil , queue: . main) { [ weak self] _ in
53
+ willEnterForegroundObserver = NotificationCenter . default. addObserver ( forName: UIApplication . willEnterForegroundNotification, object: nil , queue: . main) { [ weak self] _ in
48
54
self ? . viewModel. refreshVaultLockStates ( ) . catch { error in
49
55
DDLogError ( " Refresh vault lock states failed with error: \( error) " )
50
56
}
51
57
}
58
+
59
+ #if !ALWAYS_PREMIUM
60
+ fullVersionPurchasedObserver = NotificationCenter . default. addObserver ( forName: . purchasedFullVersionNotification, object: nil , queue: . main) { [ weak self] _ in
61
+ self ? . dismissBanner ( )
62
+ }
63
+ checkAndShowBanner ( )
64
+ #endif
52
65
}
53
66
54
67
override func viewWillAppear( _ animated: Bool ) {
@@ -108,4 +121,94 @@ class VaultListViewController: ListViewController<VaultCellViewModel> {
108
121
coordinator? . showVaultDetail ( for: vaultCellViewModel. vault)
109
122
}
110
123
}
124
+
125
+ // MARK: - Discount Banner
126
+
127
+ #if !ALWAYS_PREMIUM
128
+ private func checkAndShowBanner( ) {
129
+ let currentYear = Calendar . current. component ( . year, from: Date ( ) )
130
+ let currentMonth = Calendar . current. component ( . month, from: Date ( ) )
131
+ if currentYear == 2024 , currentMonth == 12 , !( cryptomatorSettings. fullVersionUnlocked || cryptomatorSettings. hasRunningSubscription) , !cryptomatorSettings. december2024BannerDismissed {
132
+ showBanner ( )
133
+ }
134
+ }
135
+
136
+ private func showBanner( ) {
137
+ let banner = UIView ( )
138
+ banner. backgroundColor = UIColor . cryptomatorPrimary
139
+ banner. translatesAutoresizingMaskIntoConstraints = false
140
+ banner. layer. cornerRadius = 12
141
+ banner. layer. masksToBounds = true
142
+
143
+ let emojiLabel = UILabel ( )
144
+ emojiLabel. text = " 🎁 "
145
+ emojiLabel. translatesAutoresizingMaskIntoConstraints = false
146
+ emojiLabel. setContentHuggingPriority ( . required, for: . horizontal)
147
+ emojiLabel. setContentCompressionResistancePriority ( . required, for: . horizontal)
148
+
149
+ let textLabel = UILabel ( )
150
+ textLabel. text = " Lifetime License is 33%* off in December! "
151
+ textLabel. textColor = . white
152
+ textLabel. font = UIFont . preferredFont ( forTextStyle: . footnote)
153
+ textLabel. adjustsFontSizeToFitWidth = true
154
+ textLabel. minimumScaleFactor = 0.5
155
+ textLabel. numberOfLines = 2
156
+ textLabel. translatesAutoresizingMaskIntoConstraints = false
157
+
158
+ let dismissButton = UIButton ( type: . close)
159
+ dismissButton. addTarget ( self , action: #selector( dismissBanner) , for: . touchUpInside)
160
+ dismissButton. translatesAutoresizingMaskIntoConstraints = false
161
+ dismissButton. setContentHuggingPriority ( . required, for: . horizontal)
162
+ dismissButton. setContentCompressionResistancePriority ( . required, for: . horizontal)
163
+
164
+ banner. addSubview ( emojiLabel)
165
+ banner. addSubview ( textLabel)
166
+ banner. addSubview ( dismissButton)
167
+
168
+ NSLayoutConstraint . activate ( [
169
+ emojiLabel. leadingAnchor. constraint ( equalTo: banner. leadingAnchor, constant: 16 ) ,
170
+ emojiLabel. centerYAnchor. constraint ( equalTo: banner. centerYAnchor) ,
171
+
172
+ textLabel. leadingAnchor. constraint ( equalTo: emojiLabel. trailingAnchor, constant: 8 ) ,
173
+ textLabel. centerYAnchor. constraint ( equalTo: banner. centerYAnchor) ,
174
+
175
+ dismissButton. leadingAnchor. constraint ( equalTo: textLabel. trailingAnchor, constant: 8 ) ,
176
+ dismissButton. trailingAnchor. constraint ( equalTo: banner. trailingAnchor, constant: - 16 ) ,
177
+ dismissButton. centerYAnchor. constraint ( equalTo: banner. centerYAnchor)
178
+ ] )
179
+
180
+ let tapGestureRecognizer = UITapGestureRecognizer ( target: self , action: #selector( bannerTapped) )
181
+ banner. addGestureRecognizer ( tapGestureRecognizer)
182
+
183
+ view. addSubview ( banner)
184
+
185
+ NSLayoutConstraint . activate ( [
186
+ banner. leadingAnchor. constraint ( equalTo: view. leadingAnchor, constant: 16 ) ,
187
+ banner. trailingAnchor. constraint ( equalTo: view. trailingAnchor, constant: - 16 ) ,
188
+ banner. bottomAnchor. constraint ( equalTo: view. safeAreaLayoutGuide. bottomAnchor, constant: - 16 ) ,
189
+ banner. centerXAnchor. constraint ( equalTo: view. centerXAnchor) ,
190
+ banner. heightAnchor. constraint ( equalToConstant: 50 )
191
+ ] )
192
+
193
+ bannerView = banner
194
+ }
195
+
196
+ @objc private func dismissBanner( ) {
197
+ UIView . animate ( withDuration: 0.3 , animations: {
198
+ self . bannerView? . alpha = 0
199
+ } , completion: { _ in
200
+ self . bannerView? . removeFromSuperview ( )
201
+ self . bannerView = nil
202
+ } )
203
+ CryptomatorUserDefaults . shared. december2024BannerDismissed = true
204
+ }
205
+
206
+ @objc private func bannerTapped( ) {
207
+ coordinator? . showPurchase ( )
208
+ }
209
+ #endif
210
+ }
211
+
212
+ extension Notification . Name {
213
+ static let purchasedFullVersionNotification = Notification . Name ( " PurchasedFullVersionNotification " )
111
214
}
0 commit comments