Skip to content

Commit 727673c

Browse files
committed
Merge develop into feature/hub-sharebutton
2 parents 3b313d5 + dc04fa5 commit 727673c

33 files changed

+340
-206
lines changed

.github/workflows/build.yml

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,22 @@ jobs:
1111
runs-on: [self-hosted, macOS, ARM64]
1212
env:
1313
DERIVED_DATA_PATH: 'DerivedData'
14-
DEVICE: 'iPhone 15 Pro'
14+
DEVICE: 'iPhone 17 Pro'
1515
strategy:
1616
matrix:
1717
config: ['freemium', 'premium']
1818
steps:
1919
- uses: actions/checkout@v4
20+
with:
21+
# Disable shallow clone for SonarCloud analysis
22+
# https://docs.sonarsource.com/sonarqube-cloud/advanced-setup/ci-based-analysis/github-actions-for-sonarcloud
23+
fetch-depth: 0
2024
- uses: actions/cache@v4
2125
with:
2226
path: .build
2327
key: ${{ runner.os }}-spm-${{ hashFiles('**/Package.resolved') }}
2428
restore-keys: |
2529
${{ runner.os }}-spm-
26-
- name: Install SwiftLint
27-
run: brew install swiftlint
2830
- name: Run process.sh script
2931
run: |
3032
./Scripts/process.sh
@@ -33,8 +35,6 @@ jobs:
3335
run: |
3436
cd fastlane
3537
./scripts/create-cloud-access-secrets.sh
36-
- name: Select Xcode 15.3
37-
run: sudo xcode-select -s /Applications/Xcode_15.3.app
3838
- name: Configuration for freemium
3939
if: ${{ matrix.config == 'freemium' }}
4040
run: |
@@ -44,15 +44,17 @@ jobs:
4444
run: |
4545
echo "BUILD_CMD=SWIFT_ACTIVE_COMPILATION_CONDITIONS='\$(inherited) ALWAYS_PREMIUM'" >> $GITHUB_ENV
4646
- name: Build
47-
run: set -o pipefail && env NSUnbufferedIO=YES xcodebuild clean build-for-testing -scheme 'AllTests' -destination "name=$DEVICE" -derivedDataPath $DERIVED_DATA_PATH ${{ env.BUILD_CMD }} | xcpretty
47+
run: set -o pipefail && env NSUnbufferedIO=YES xcodebuild clean build-for-testing -scheme 'AllTests' -destination "name=$DEVICE" -derivedDataPath $DERIVED_DATA_PATH ${{ env.BUILD_CMD }} | xcbeautify
4848
- name: Test
49-
run: set -o pipefail && env NSUnbufferedIO=YES xcodebuild test-without-building -xctestrun $(find . -type f -name "*.xctestrun") -destination "name=$DEVICE" -derivedDataPath $DERIVED_DATA_PATH | xcpretty
50-
- name: Upload code coverage report
49+
run: set -o pipefail && env NSUnbufferedIO=YES xcodebuild test-without-building -xctestrun $(find . -type f -name "*.xctestrun") -destination "name=$DEVICE" -derivedDataPath $DERIVED_DATA_PATH | xcbeautify
50+
- name: Generate coverage report
5151
if: ${{ matrix.config == 'freemium' }}
5252
run: |
53-
gem install slather
54-
slather coverage -x --build-directory $DERIVED_DATA_PATH --ignore "$DERIVED_DATA_PATH/SourcePackages/*" --scheme AllTests Cryptomator.xcodeproj
55-
bash <(curl -Ls https://coverage.codacy.com/get.sh)
53+
xcresult_path=$(find $DERIVED_DATA_PATH/Logs/Test -name "*.xcresult" | head -n 1)
54+
bash Scripts/xccov-to-sonarqube-generic.sh "$xcresult_path" > sonarqube-generic-coverage.xml
55+
- name: SonarCloud Scan
56+
if: ${{ matrix.config == 'freemium' }}
57+
uses: SonarSource/[email protected]
5658
env:
57-
CODACY_PROJECT_TOKEN: ${{ secrets.CODACY_PROJECT_TOKEN }}
59+
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
5860
continue-on-error: true

.swiftformat

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
--minversion 0.49.2
1+
--minversion 0.58.3
2+
--exclude DerivedData
23

34
# format options
45

.xcode-version

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
26.0.1

Cryptomator.xcodeproj/project.pbxproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3396,7 +3396,7 @@
33963396
GCC_WARN_UNUSED_FUNCTION = YES;
33973397
GCC_WARN_UNUSED_VARIABLE = YES;
33983398
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
3399-
MARKETING_VERSION = 2.7.1;
3399+
MARKETING_VERSION = 2.7.2;
34003400
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
34013401
MTL_FAST_MATH = YES;
34023402
ONLY_ACTIVE_ARCH = YES;
@@ -3458,7 +3458,7 @@
34583458
GCC_WARN_UNUSED_FUNCTION = YES;
34593459
GCC_WARN_UNUSED_VARIABLE = YES;
34603460
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
3461-
MARKETING_VERSION = 2.7.1;
3461+
MARKETING_VERSION = 2.7.2;
34623462
MTL_ENABLE_DEBUG_INFO = NO;
34633463
MTL_FAST_MATH = YES;
34643464
OTHER_SWIFT_FLAGS = "-Xfrontend -warn-long-expression-type-checking=200 -Xfrontend -warn-long-function-bodies=200";

Cryptomator/Common/CloudAccountList/AccountListViewModel.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,6 @@ class AccountListViewModel: AccountListViewModelProtocol {
220220
let removedAccountInfo = accountInfos.remove(at: index)
221221
do {
222222
try cloudAuthenticator.deauthenticate(account: removedAccountInfo.cloudProviderAccount)
223-
try updateAccountListPositions()
224223
} catch {
225224
removedRow = false
226225
throw error

Cryptomator/MainCoordinator.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ class MainCoordinator: NSObject, Coordinator, UINavigationControllerDelegate {
7878
rootViewController.showDetailViewController(detailNavigationController, sender: nil)
7979
}
8080

81-
// Temporarily added for Summer 2025 Sale
81+
// Temporarily added for Autumn 2025 Sale
8282
func showPurchase() {
8383
let modalNavigationController = BaseNavigationController()
8484
let child = PurchaseCoordinator(navigationController: modalNavigationController)
@@ -124,7 +124,7 @@ extension MainCoordinator: StoreObserverDelegate {
124124
switch transaction {
125125
case .fullVersion, .yearlySubscription:
126126
showFullVersionAlert()
127-
// Temporarily added for Summer 2025 Sale
127+
// Temporarily added for Autumn 2025 Sale
128128
NotificationCenter.default.post(name: .purchasedFullVersionNotification, object: nil)
129129
case let .freeTrial(expiresOn):
130130
showTrialAlert(expirationDate: expiresOn)

Cryptomator/Purchase/PurchaseCoordinator.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ class PurchaseCoordinator: Coordinator {
5454
}
5555
self.unlockedPro()
5656
}
57-
// Temporarily added for Summer 2025 Sale
57+
// Temporarily added for Autumn 2025 Sale
5858
NotificationCenter.default.post(name: .purchasedFullVersionNotification, object: nil)
5959
}
6060

Cryptomator/Purchase/PurchaseViewModel.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ class PurchaseViewModel: BaseIAPViewModel, ProductFetching {
3333
return LocalizedString.getValue("purchase.title")
3434
}
3535

36-
// Temporarily added for Summer 2025 Sale
36+
// Temporarily added for Autumn 2025 Sale
3737
override var infoText: NSAttributedString? {
38-
if SalePromo.isSummer2025Active() {
38+
if SalePromo.isAutumn2025Active() {
3939
return NSAttributedString(
4040
string: "*Note: The discount amount may vary by region.",
4141
attributes: [
@@ -91,8 +91,8 @@ class PurchaseViewModel: BaseIAPViewModel, ProductFetching {
9191

9292
private func addLifetimeLicenseItem() {
9393
if let product = products[.fullVersion], let localizedPrice = product.localizedPrice {
94-
// Temporarily added for Summer 2025 Sale
95-
let productDetail = SalePromo.isSummer2025Active() ? "\(SalePromo.summer2025Emoji) \(SalePromo.summer2025Discount)" : nil
94+
// Temporarily added for Autumn 2025 Sale
95+
let productDetail = SalePromo.isAutumn2025Active() ? "\(SalePromo.autumn2025Emoji) \(SalePromo.autumn2025Discount)" : nil
9696
let viewModel = PurchaseCellViewModel(productName: LocalizedString.getValue("purchase.product.lifetimeLicense"),
9797
productDetail: productDetail,
9898
price: localizedPrice,

Cryptomator/Purchase/SalePromo.swift

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,22 @@ struct SalePromo {
1313
@Dependency(\.cryptomatorSettings) private var cryptomatorSettings
1414

1515
static let shared = SalePromo()
16-
static let summer2025Emoji = "☀️"
17-
static let summer2025Discount = "25%* off until June 30"
16+
static let autumn2025Emoji = "🍁"
17+
static let autumn2025Discount = "25%* off until September 30"
1818

19-
static func isSummer2025Active() -> Bool {
20-
let saleStartComponents = DateComponents(year: 2025, month: 6, day: 1)
21-
let saleEndComponents = DateComponents(year: 2025, month: 6, day: 30)
19+
static func isAutumn2025Active() -> Bool {
20+
let saleStartComponents = DateComponents(year: 2025, month: 9, day: 22)
21+
let saleEndComponents = DateComponents(year: 2025, month: 9, day: 30)
2222
guard let saleStartDate = Calendar.current.date(from: saleStartComponents), let saleEndDate = Calendar.current.date(from: saleEndComponents) else {
2323
return false
2424
}
2525
let now = Date()
2626
return now >= saleStartDate && now <= saleEndDate
2727
}
2828

29-
func shouldShowSummer2025Banner() -> Bool {
29+
func shouldShowAutumn2025Banner() -> Bool {
3030
#if !ALWAYS_PREMIUM
31-
return SalePromo.isSummer2025Active() && !(cryptomatorSettings.fullVersionUnlocked || cryptomatorSettings.hasRunningSubscription) && !cryptomatorSettings.summer2025BannerDismissed
31+
return SalePromo.isAutumn2025Active() && !(cryptomatorSettings.fullVersionUnlocked || cryptomatorSettings.hasRunningSubscription) && !cryptomatorSettings.autumn2025BannerDismissed
3232
#else
3333
return false
3434
#endif

Cryptomator/VaultList/VaultListViewController.swift

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ class VaultListViewController: ListViewController<VaultCellViewModel> {
2121
@Dependency(\.fullVersionChecker) private var fullVersionChecker
2222

2323
#if !ALWAYS_PREMIUM
24-
private var summer2025BannerView: UIView?
24+
private var autumn2025BannerView: UIView?
2525
private var fullVersionPurchasedObserver: NSObjectProtocol?
2626
#endif
2727

@@ -57,10 +57,10 @@ class VaultListViewController: ListViewController<VaultCellViewModel> {
5757

5858
#if !ALWAYS_PREMIUM
5959
fullVersionPurchasedObserver = NotificationCenter.default.addObserver(forName: .purchasedFullVersionNotification, object: nil, queue: .main) { [weak self] _ in
60-
self?.dismissSummer2025Banner()
60+
self?.dismissAutumn2025Banner()
6161
}
62-
if SalePromo.shared.shouldShowSummer2025Banner() {
63-
showSummer2025Banner()
62+
if SalePromo.shared.shouldShowAutumn2025Banner() {
63+
showAutumn2025Banner()
6464
}
6565
#endif
6666
}
@@ -126,21 +126,21 @@ class VaultListViewController: ListViewController<VaultCellViewModel> {
126126
// MARK: - Sale Promo Banner
127127

128128
#if !ALWAYS_PREMIUM
129-
private func showSummer2025Banner() {
129+
private func showAutumn2025Banner() {
130130
let banner = UIView()
131131
banner.backgroundColor = UIColor.cryptomatorPrimary
132132
banner.translatesAutoresizingMaskIntoConstraints = false
133133
banner.layer.cornerRadius = 12
134134
banner.layer.masksToBounds = true
135135

136136
let emojiLabel = UILabel()
137-
emojiLabel.text = SalePromo.summer2025Emoji
137+
emojiLabel.text = SalePromo.autumn2025Emoji
138138
emojiLabel.translatesAutoresizingMaskIntoConstraints = false
139139
emojiLabel.setContentHuggingPriority(.required, for: .horizontal)
140140
emojiLabel.setContentCompressionResistancePriority(.required, for: .horizontal)
141141

142142
let textLabel = UILabel()
143-
textLabel.text = "Lifetime License is \(SalePromo.summer2025Discount)!"
143+
textLabel.text = "Lifetime License is \(SalePromo.autumn2025Discount)!"
144144
textLabel.textColor = .white
145145
textLabel.font = UIFont.preferredFont(forTextStyle: .footnote)
146146
textLabel.adjustsFontSizeToFitWidth = true
@@ -149,7 +149,7 @@ class VaultListViewController: ListViewController<VaultCellViewModel> {
149149
textLabel.translatesAutoresizingMaskIntoConstraints = false
150150

151151
let dismissButton = UIButton(type: .close)
152-
dismissButton.addTarget(self, action: #selector(dismissSummer2025Banner), for: .touchUpInside)
152+
dismissButton.addTarget(self, action: #selector(dismissAutumn2025Banner), for: .touchUpInside)
153153
dismissButton.translatesAutoresizingMaskIntoConstraints = false
154154
dismissButton.setContentHuggingPriority(.required, for: .horizontal)
155155
dismissButton.setContentCompressionResistancePriority(.required, for: .horizontal)
@@ -170,7 +170,7 @@ class VaultListViewController: ListViewController<VaultCellViewModel> {
170170
dismissButton.centerYAnchor.constraint(equalTo: banner.centerYAnchor)
171171
])
172172

173-
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(summer2025BannerTapped))
173+
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(autumn2025BannerTapped))
174174
banner.addGestureRecognizer(tapGestureRecognizer)
175175

176176
view.addSubview(banner)
@@ -183,20 +183,20 @@ class VaultListViewController: ListViewController<VaultCellViewModel> {
183183
banner.heightAnchor.constraint(equalToConstant: 50)
184184
])
185185

186-
summer2025BannerView = banner
186+
autumn2025BannerView = banner
187187
}
188188

189-
@objc private func dismissSummer2025Banner() {
189+
@objc private func dismissAutumn2025Banner() {
190190
UIView.animate(withDuration: 0.3, animations: {
191-
self.summer2025BannerView?.alpha = 0
191+
self.autumn2025BannerView?.alpha = 0
192192
}, completion: { _ in
193-
self.summer2025BannerView?.removeFromSuperview()
194-
self.summer2025BannerView = nil
193+
self.autumn2025BannerView?.removeFromSuperview()
194+
self.autumn2025BannerView = nil
195195
})
196-
CryptomatorUserDefaults.shared.summer2025BannerDismissed = true
196+
CryptomatorUserDefaults.shared.autumn2025BannerDismissed = true
197197
}
198198

199-
@objc private func summer2025BannerTapped() {
199+
@objc private func autumn2025BannerTapped() {
200200
coordinator?.showPurchase()
201201
}
202202
#endif

0 commit comments

Comments
 (0)