Skip to content

Commit f6729f7

Browse files
Show purchase status in settings (#426)
Co-authored-by: Tobias Hagemann <tobias.hagemann@skymatic.de>
1 parent 77d2121 commit f6729f7

File tree

12 files changed

+58
-30
lines changed

12 files changed

+58
-30
lines changed

Cryptomator/AddVault/OpenExistingVault/OpenExistingVaultChooseFolderViewController.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ class OpenExistingVaultChooseFolderViewController: ChooseFolderViewController {
4545

4646
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
4747
if viewModel.foundMasterkey {
48-
let cell = addVaultButtonViewModel.type.init()
48+
let cell = addVaultButtonViewModel.type.init(style: addVaultButtonViewModel.cellStyle, reuseIdentifier: nil)
4949
cell.configure(with: addVaultButtonViewModel)
5050
return cell
5151
} else {

Cryptomator/Common/Cells/BindableTableViewCellViewModel.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ class TableViewCellViewModel: Hashable {
3939
fatalError("not implemented")
4040
}
4141

42+
var cellStyle: UITableViewCell.CellStyle {
43+
return .default
44+
}
45+
4246
private let identifier = UUID()
4347

4448
static func == (lhs: TableViewCellViewModel, rhs: TableViewCellViewModel) -> Bool {

Cryptomator/Common/Cells/ButtonCellViewModel.swift

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,16 @@
99
import UIKit
1010

1111
class ButtonCellViewModel<T>: BindableTableViewCellViewModel {
12-
override var type: ConfigurableTableViewCell.Type { ButtonTableViewCell.self }
12+
private let preferredCellStyle: UITableViewCell.CellStyle
13+
override var cellStyle: UITableViewCell.CellStyle { preferredCellStyle }
1314
let action: T
14-
init(action: T, title: String, titleTextColor: UIColor? = .cryptomatorPrimary, detailTitle: String? = nil, isEnabled: Bool = true, selectionStyle: UITableViewCell.SelectionStyle = .default, accessoryType: UITableViewCell.AccessoryType = .none) {
15+
init(action: T, title: String, titleTextColor: UIColor? = .cryptomatorPrimary, detailTitle: String? = nil, image: UIImage? = nil, isEnabled: Bool = true, selectionStyle: UITableViewCell.SelectionStyle = .default, accessoryType: UITableViewCell.AccessoryType = .none, cellStyle: UITableViewCell.CellStyle = .value1) {
1516
self.action = action
16-
super.init(title: title, titleTextColor: titleTextColor, detailTitle: detailTitle, isEnabled: isEnabled, selectionStyle: selectionStyle, accessoryType: accessoryType)
17+
self.preferredCellStyle = cellStyle
18+
super.init(title: title, titleTextColor: titleTextColor, detailTitle: detailTitle, image: image, isEnabled: isEnabled, selectionStyle: selectionStyle, accessoryType: accessoryType)
1719
}
1820

19-
static func createDisclosureButton(action: T, title: String, detailTitle: String? = nil, accessoryType: UITableViewCell.AccessoryType = .disclosureIndicator, isEnabled: Bool = true) -> ButtonCellViewModel<T> {
20-
return ButtonCellViewModel(action: action, title: title, titleTextColor: nil, detailTitle: detailTitle, isEnabled: isEnabled, accessoryType: accessoryType)
21-
}
22-
}
23-
24-
class ButtonTableViewCell: TableViewCell {
25-
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
26-
super.init(style: .value1, reuseIdentifier: reuseIdentifier)
21+
static func createDisclosureButton(action: T, title: String, detailTitle: String? = nil, image: UIImage? = nil, accessoryType: UITableViewCell.AccessoryType = .disclosureIndicator, isEnabled: Bool = true, cellStyle: UITableViewCell.CellStyle = .value1) -> ButtonCellViewModel<T> {
22+
return ButtonCellViewModel(action: action, title: title, titleTextColor: nil, detailTitle: detailTitle, image: image, isEnabled: isEnabled, accessoryType: accessoryType, cellStyle: cellStyle)
2723
}
2824
}

Cryptomator/Common/Cells/LoadingButtonCell.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
import UIKit
1010

11-
class LoadingButtonCell: ButtonTableViewCell {
11+
class LoadingButtonCell: TableViewCell {
1212
private lazy var loadingIndicator: UIActivityIndicatorView = {
1313
let loadingIndicator = UIActivityIndicatorView(style: .medium)
1414
loadingIndicator.hidesWhenStopped = true

Cryptomator/Common/Cells/SystemSymbolButtonCell.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import Foundation
1010
import UIKit
1111

12-
class SystemSymbolButtonCell: ButtonTableViewCell {
12+
class SystemSymbolButtonCell: TableViewCell {
1313
override func configure(with viewModel: TableViewCellViewModel) {
1414
super.configure(with: viewModel)
1515
guard let viewModel = viewModel as? SystemSymbolNameProviding else {

Cryptomator/Common/ChooseFolder/CreateNewFolderViewController.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ class CreateNewFolderViewController: SingleSectionStaticUITableViewController {
3535

3636
override func configureDataSource() {
3737
dataSource = BaseDiffableDataSource<SingleSection, TableViewCellViewModel>(viewModel: viewModel, tableView: tableView) { _, _, cellViewModel -> UITableViewCell? in
38-
let cell = cellViewModel.type.init()
38+
let cell = cellViewModel.type.init(style: cellViewModel.cellStyle, reuseIdentifier: nil)
3939
cell.configure(with: cellViewModel)
4040
if let textFieldCell = cell as? TextFieldCell {
4141
let imageConfiguration = UIImage.SymbolConfiguration(font: UIFont.preferredFont(forTextStyle: .title2))

Cryptomator/Common/StaticUITableViewController.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ class StaticUITableViewController<SectionType: Hashable>: BaseUITableViewControl
2727

2828
func configureDataSource() {
2929
dataSource = BaseDiffableDataSource<SectionType, TableViewCellViewModel>(viewModel: viewModel, tableView: tableView) { _, _, cellViewModel -> UITableViewCell? in
30-
let cell = cellViewModel.type.init()
30+
let cell = cellViewModel.type.init(style: cellViewModel.cellStyle, reuseIdentifier: nil)
3131
cell.configure(with: cellViewModel)
3232
return cell
3333
}

Cryptomator/Purchase/Cells/TrialCell.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,7 @@ struct TrialCellViewModel: Hashable {
7676
var expirationText: String {
7777
let formatter = DateFormatter()
7878
formatter.dateStyle = .short
79-
let formattedExpirationDate = formatter.string(for: expirationDate) ?? "Invalid Date"
80-
return String(format: LocalizedString.getValue("purchase.product.trial.expirationDate"), formattedExpirationDate)
79+
return String(format: LocalizedString.getValue("purchase.product.trial.expirationDate"), formatter.string(from: expirationDate))
8180
}
8281

8382
let expirationDate: Date

Cryptomator/Purchase/PurchaseAlert.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@ enum PurchaseAlert {
1818
static func showForTrial(title: String, expirationDate: Date, on presentingViewController: UIViewController) -> Promise<Void> {
1919
let formatter = DateFormatter()
2020
formatter.dateStyle = .short
21-
let formattedExpireDate = formatter.string(for: expirationDate) ?? "Invalid Date"
22-
let message = String(format: LocalizedString.getValue("purchase.restorePurchase.validTrialFound.alert.message"), formattedExpireDate)
21+
let message = String(format: LocalizedString.getValue("purchase.restorePurchase.validTrialFound.alert.message"), formatter.string(from: expirationDate))
2322
return showAlert(title: title, message: message, on: presentingViewController)
2423
}
2524

Cryptomator/Settings/SettingsViewModel.swift

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ enum SettingsButtonAction: String {
2828
}
2929

3030
enum SettingsSection: Int {
31-
case cloudServiceSection = 0
31+
case unlockFullVersionSection = 0
32+
case cloudServiceSection
3233
case cacheSection
3334
case aboutSection
3435
case debugSection
@@ -44,12 +45,25 @@ class SettingsViewModel: TableViewModel<SettingsSection> {
4445
return _sections
4546
}
4647

48+
override func getFooterTitle(for section: Int) -> String? {
49+
guard sections[section].id == .aboutSection, hasFullVersion else { return nil }
50+
return LocalizedString.getValue("settings.aboutCryptomator.hasFullVersion.footer")
51+
}
52+
4753
var showDebugModeWarning: AnyPublisher<Void, Never> {
4854
return showDebugModeWarningPublisher.eraseToAnyPublisher()
4955
}
5056

57+
private var hasFullVersion: Bool {
58+
cryptomatorSettings.hasRunningSubscription || cryptomatorSettings.fullVersionUnlocked
59+
}
60+
5161
private var _sections: [Section<SettingsSection>] {
52-
return [
62+
var sections: [Section<SettingsSection>] = []
63+
if !hasFullVersion {
64+
sections.append(Section(id: .unlockFullVersionSection, elements: [unlockFullVersionCellViewModel]))
65+
}
66+
sections.append(contentsOf: [
5367
Section(id: .cloudServiceSection, elements: [
5468
ButtonCellViewModel.createDisclosureButton(action: SettingsButtonAction.showCloudServices, title: LocalizedString.getValue("settings.cloudServices"))
5569
]),
@@ -67,24 +81,37 @@ class SettingsViewModel: TableViewModel<SettingsSection> {
6781
ButtonCellViewModel(action: SettingsButtonAction.showContact, title: LocalizedString.getValue("settings.contact")),
6882
ButtonCellViewModel(action: SettingsButtonAction.showRateApp, title: LocalizedString.getValue("settings.rateApp"))
6983
])
70-
]
84+
])
85+
return sections
7186
}
7287

7388
private var aboutSectionElements: [TableViewCellViewModel] {
74-
var elements = [ButtonCellViewModel.createDisclosureButton(action: SettingsButtonAction.showAbout, title: LocalizedString.getValue("settings.aboutCryptomator"))]
89+
var elements: [TableViewCellViewModel] = [
90+
ButtonCellViewModel.createDisclosureButton(action: SettingsButtonAction.showAbout, title: LocalizedString.getValue("settings.aboutCryptomator"))
91+
]
7592
if cryptomatorSettings.hasRunningSubscription {
76-
elements.append(.init(action: .showManageSubscriptions, title: LocalizedString.getValue("settings.manageSubscriptions")))
77-
elements.append(.init(action: .restorePurchase, title: LocalizedString.getValue("purchase.restorePurchase.button")))
78-
} else if !cryptomatorSettings.fullVersionUnlocked {
79-
elements.append(ButtonCellViewModel.createDisclosureButton(action: SettingsButtonAction.showUnlockFullVersion, title: LocalizedString.getValue("settings.unlockFullVersion")))
93+
elements.append(ButtonCellViewModel.createDisclosureButton(action: SettingsButtonAction.showManageSubscriptions, title: LocalizedString.getValue("settings.manageSubscriptions")))
8094
}
8195
return elements
8296
}
8397

98+
private var unlockFullVersionCellViewModel: ButtonCellViewModel<SettingsButtonAction> {
99+
let detailTitle: String
100+
if let trialExpirationDate = cryptomatorSettings.trialExpirationDate, trialExpirationDate > Date() {
101+
let formatter = DateFormatter()
102+
formatter.dateStyle = .short
103+
detailTitle = String(format: LocalizedString.getValue("settings.unlockFullVersion.trialExpirationDate"), formatter.string(from: trialExpirationDate))
104+
} else {
105+
detailTitle = LocalizedString.getValue("settings.unlockFullVersion.detail")
106+
}
107+
let image = UIImage(systemName: "checkmark.seal.fill", withConfiguration: UIImage.SymbolConfiguration(pointSize: 22))
108+
return ButtonCellViewModel.createDisclosureButton(action: .showUnlockFullVersion, title: LocalizedString.getValue("settings.unlockFullVersion"), detailTitle: detailTitle, image: image, cellStyle: .subtitle)
109+
}
110+
84111
private let cacheSizeCellViewModel = LoadingWithLabelCellViewModel(title: LocalizedString.getValue("settings.cacheSize"))
85112
private let clearCacheButtonCellViewModel = ButtonCellViewModel<SettingsButtonAction>(action: .clearCache, title: LocalizedString.getValue("settings.clearCache"), isEnabled: false)
86-
87113
private var cryptomatorSettings: CryptomatorSettings
114+
88115
private lazy var debugModeViewModel: SwitchCellViewModel = {
89116
let viewModel = SwitchCellViewModel(title: LocalizedString.getValue("settings.debugMode"), isOn: cryptomatorSettings.debugModeEnabled)
90117
bindDebugModeViewModel(viewModel)

0 commit comments

Comments
 (0)