Last active
March 9, 2018 22:00
-
-
Save dlo/04d728c1e0ffadd200f62bb6fc60f390 to your computer and use it in GitHub Desktop.
Simple review prompt point system for iOS apps, with points and half-lives assigned to in-app actions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import UIKit | |
import StoreKit | |
enum StoreReviewValue: Int, Codable { | |
case high | |
case medium | |
case low | |
var value: NSDecimalNumber { | |
switch self { | |
case .high: return 100 | |
case .medium: return 10 | |
case .low: return 1 | |
} | |
} | |
} | |
enum StoreReviewHalfLife { | |
case hour | |
case day | |
case week | |
case month | |
var seconds: Int { | |
switch self { | |
case .hour: return 60*60 | |
case .day: return StoreReviewHalfLife.hour.seconds * 24 | |
case .week: return StoreReviewHalfLife.day.seconds * 7 | |
case .month: return StoreReviewHalfLife.week.seconds * 4 | |
} | |
} | |
} | |
struct StoreReviewAction: Codable { | |
var initialValue: StoreReviewValue | |
var halfLife: Int | |
var createdOn: Date | |
var value: NSDecimalNumber { | |
let now = Date() | |
let interval = now.timeIntervalSince(createdOn) | |
let exponent = NSDecimalNumber(value: pow(0.5, interval)) | |
return initialValue.value.multiplying(by: exponent) | |
} | |
init(value: StoreReviewValue, halfLife: Int) { | |
self.initialValue = value | |
self.halfLife = halfLife | |
createdOn = Date() | |
} | |
} | |
struct StoreReviewPointsManager { | |
var actions: [StoreReviewAction] = [] | |
var promptThreshold: NSDecimalNumber! | |
var data: Data? { | |
let encoder = JSONEncoder() | |
return try? encoder.encode(actions) | |
} | |
var value: NSDecimalNumber { | |
return actions.reduce(NSDecimalNumber.zero, { | |
$1.value.adding($0) | |
}) | |
} | |
let fileURL: URL = { | |
let directories = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask) | |
guard let documentsDirectory = directories.first else { | |
return URL(fileURLWithPath: "/tmp/points.txt") | |
} | |
return documentsDirectory.appendingPathComponent("/points.txt") | |
}() | |
// MARK: - | |
init(threshold: NSDecimalNumber) { | |
let decoder = JSONDecoder() | |
if let data = try? Data(contentsOf: fileURL), | |
let _actions = try? decoder.decode([StoreReviewAction].self, from: data) { | |
actions = _actions | |
} | |
promptThreshold = threshold | |
} | |
// MARK: - | |
func save() throws { | |
try data?.write(to: fileURL) | |
} | |
mutating func addAction(value: StoreReviewValue, halfLife: StoreReviewHalfLife) { | |
actions.append(StoreReviewAction(value: value, halfLife: halfLife.seconds)) | |
if self.value.compare(promptThreshold) == .orderedDescending { | |
SKStoreReviewController.requestReview() | |
actions.removeAll() | |
} | |
} | |
} | |
var manager = StoreReviewPointsManager(threshold: 10) | |
manager.addAction(value: .high, halfLife: .hour) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
StoreReviewAction
forgot to use itshalfLife
! Should look more like: