Skip to content

Commit 9f1ee8e

Browse files
committed
[698] Resolve comments
1 parent 27533b8 commit 9f1ee8e

9 files changed

Lines changed: 53 additions & 50 deletions

File tree

template/Modules/Data/Sources/Extensions/Container+Data.swift

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,4 @@ extension Container {
5050
public var ratingPromptStorage: Factory<RatingPromptStorageProtocol> {
5151
self { RatingPromptStorage(userDefaultsManager: self.userDefaultsManager()) }.singleton
5252
}
53-
54-
public var ratingPromptPresenter: Factory<RatingPromptPresenterProtocol> {
55-
self { DefaultRatingPromptPresenter() }.singleton
56-
}
57-
5853
}

template/Modules/Data/Sources/Repositories/RatingPromptStorage.swift

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import Foundation
44
final class RatingPromptStorage: RatingPromptStorageProtocol, @unchecked Sendable {
55

66
private let userDefaultsManager: UserDefaultsManagerProtocol
7+
private let lock = NSLock()
78

89
init(userDefaultsManager: UserDefaultsManagerProtocol) {
910
self.userDefaultsManager = userDefaultsManager
@@ -29,11 +30,12 @@ final class RatingPromptStorage: RatingPromptStorageProtocol, @unchecked Sendabl
2930
}
3031

3132
func recordAppLaunch() {
32-
// Increment launch count
33+
lock.lock()
34+
defer { lock.unlock() }
35+
3336
let currentCount = userDefaultsManager.getIntValue(for: UserDefaultsKey.ratingPromptAppLaunchCount.rawValue)
3437
userDefaultsManager.set(currentCount + 1, for: UserDefaultsKey.ratingPromptAppLaunchCount.rawValue)
3538

36-
// Set first launch date if not already set
3739
if userDefaultsManager.getDataValue(for: UserDefaultsKey.ratingPromptFirstLaunchDate.rawValue) == nil {
3840
let now = Date()
3941
if let dateData = try? JSONEncoder().encode(now) {
@@ -45,6 +47,9 @@ final class RatingPromptStorage: RatingPromptStorageProtocol, @unchecked Sendabl
4547
}
4648

4749
func recordSignificantEvent() {
50+
lock.lock()
51+
defer { lock.unlock() }
52+
4853
let currentCount = userDefaultsManager.getIntValue(for: UserDefaultsKey.ratingPromptSignificantEventCount.rawValue)
4954
userDefaultsManager.set(currentCount + 1, for: UserDefaultsKey.ratingPromptSignificantEventCount.rawValue)
5055
userDefaultsManager.synchronize()

template/Modules/Data/Sources/Services/DefaultRatingPromptPresenter.swift

Lines changed: 3 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4,46 +4,19 @@
44

55
import Domain
66
import StoreKit
7-
import UIKit
87

98
// MARK: - DefaultRatingPromptPresenter
109

1110
public final class DefaultRatingPromptPresenter: RatingPromptPresenterProtocol, @unchecked Sendable {
1211

1312
private let storeReviewController: any StoreReviewControllerProtocol
1413

15-
public convenience init() {
16-
self.init(storeReviewController: DefaultStoreReviewController())
17-
}
18-
19-
init(storeReviewController: any StoreReviewControllerProtocol) {
14+
public init(storeReviewController: any StoreReviewControllerProtocol) {
2015
self.storeReviewController = storeReviewController
2116
}
2217

2318
@MainActor
24-
public func show() async {
25-
await storeReviewController.requestReview()
26-
}
27-
}
28-
29-
// MARK: - StoreReviewControllerProtocol
30-
31-
protocol StoreReviewControllerProtocol: Sendable {
32-
33-
@MainActor
34-
func requestReview() async
35-
}
36-
37-
struct DefaultStoreReviewController: StoreReviewControllerProtocol, Sendable {
38-
39-
@MainActor
40-
func requestReview() async {
41-
guard let windowScene = UIApplication.shared.connectedScenes
42-
.compactMap({ $0 as? UIWindowScene })
43-
.first(where: { $0.activationState == .foregroundActive })
44-
else {
45-
return
46-
}
47-
SKStoreReviewController.requestReview(in: windowScene)
19+
public func show() async -> Bool {
20+
return await storeReviewController.requestReview()
4821
}
4922
}

template/Modules/Domain/Sources/Interfaces/RatingPromptPresenterProtocol.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@
55
public protocol RatingPromptPresenterProtocol: Sendable {
66

77
@MainActor
8-
func show() async
8+
func show() async -> Bool
99
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
//
2+
// StoreReviewViewControllerProtocol.swift
3+
//
4+
5+
public protocol StoreReviewControllerProtocol: Sendable {
6+
7+
@MainActor
8+
func requestReview() async -> Bool
9+
}

template/Modules/Domain/Sources/UseCases/RequestRatingPromptUseCase.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ public struct RequestRatingPromptUseCase: RequestRatingPromptUseCaseProtocol {
3737
public func callAsFunction(configuration: RatingPromptConfiguration) async -> Bool {
3838
guard shouldShowRatingPromptUseCase(configuration: configuration) else { return false }
3939

40-
await presenter.show()
40+
let didRequestPrompt = await presenter.show()
41+
guard didRequestPrompt else { return false }
4142

4243
storage.recordPromptShown(for: currentVersion())
4344

template/Modules/Domain/Sources/UseCases/ShouldShowRatingPromptUseCase.swift

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,24 +28,18 @@ public struct ShouldShowRatingPromptUseCase: ShouldShowRatingPromptUseCaseProtoc
2828
public func callAsFunction(configuration: RatingPromptConfiguration) -> Bool {
2929
let data = storage.getRatingPromptData()
3030

31-
if data.hasBeenPromptedForCurrentVersion(currentVersion) {
31+
guard !data.hasBeenPromptedForCurrentVersion(currentVersion) else {
3232
return false
3333
}
3434

35-
let daysSinceFirstLaunch = data.daysSinceFirstLaunch
36-
guard daysSinceFirstLaunch >= configuration.minimumDaysSinceFirstLaunch else {
35+
guard data.daysSinceFirstLaunch >= configuration.minimumDaysSinceFirstLaunch else {
3736
return false
3837
}
3938

40-
guard data.appLaunchCount >= configuration.minimumAppLaunches else {
41-
return false
42-
}
43-
44-
guard data.significantEventCount >= configuration.minimumSignificantEvents else {
45-
return false
46-
}
39+
let hasEnoughAppLaunches = data.appLaunchCount >= configuration.minimumAppLaunches
40+
let hasEnoughSignificantEvents = data.significantEventCount >= configuration.minimumSignificantEvents
4741

48-
return true
42+
return hasEnoughAppLaunches || hasEnoughSignificantEvents
4943
}
5044
}
5145

template/Tuist/Interfaces/SwiftUI/Sources/Application/Dependencies/Container+Application.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,8 @@ extension Container {
2525
)
2626
}
2727
}
28+
29+
var ratingPromptPresenter: Factory<RatingPromptPresenterProtocol> {
30+
self { DefaultRatingPromptPresenter(storeReviewController: StoreReviewController()) }.singleton
31+
}
2832
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//
2+
// StoreReviewController.swift
3+
//
4+
5+
import Domain
6+
import StoreKit
7+
import UIKit
8+
9+
final class StoreReviewController: StoreReviewControllerProtocol, Sendable {
10+
11+
@MainActor
12+
func requestReview() async -> Bool {
13+
guard let windowScene = UIApplication.shared.connectedScenes
14+
.compactMap({ $0 as? UIWindowScene })
15+
.first(where: { $0.activationState == .foregroundActive })
16+
else {
17+
return false
18+
}
19+
SKStoreReviewController.requestReview(in: windowScene)
20+
return true
21+
}
22+
}

0 commit comments

Comments
 (0)