125 lines
4.6 KiB
Swift
125 lines
4.6 KiB
Swift
//
|
|
// Copyright 2022 Signal Messenger, LLC
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
//
|
|
|
|
import Foundation
|
|
|
|
public class ExperienceUpgradeFinder {
|
|
|
|
// MARK: -
|
|
|
|
public class func next(transaction: GRDBReadTransaction) -> ExperienceUpgrade? {
|
|
return allKnownExperienceUpgrades(transaction: transaction.asAnyRead)
|
|
.first(where: { upgrade in
|
|
if
|
|
!upgrade.isComplete,
|
|
!upgrade.isSnoozed,
|
|
!upgrade.hasPassedNumberOfDaysToShow,
|
|
upgrade.manifest.shouldBeShown(transaction: transaction.asAnyRead)
|
|
{
|
|
return true
|
|
}
|
|
|
|
return false
|
|
})
|
|
}
|
|
|
|
public class func markAsViewed(experienceUpgrade: ExperienceUpgrade, transaction: GRDBWriteTransaction) {
|
|
Logger.info("marking experience upgrade as seen \(experienceUpgrade.uniqueId)")
|
|
experienceUpgrade.markAsViewed(transaction: transaction.asAnyWrite)
|
|
}
|
|
|
|
public class func markAsSnoozed(experienceUpgrade: ExperienceUpgrade, transaction: GRDBWriteTransaction) {
|
|
Logger.info("marking experience upgrade as snoozed \(experienceUpgrade.uniqueId)")
|
|
|
|
experienceUpgrade.markAsSnoozed(transaction: transaction.asAnyWrite)
|
|
}
|
|
|
|
public class func markAsComplete(
|
|
experienceUpgradeManifest manifest: ExperienceUpgradeManifest,
|
|
transaction: GRDBWriteTransaction
|
|
) {
|
|
markAsComplete(
|
|
experienceUpgrade: ExperienceUpgrade.makeNew(withManifest: manifest),
|
|
transaction: transaction
|
|
)
|
|
}
|
|
|
|
public class func markAsComplete(experienceUpgrade: ExperienceUpgrade, transaction: GRDBWriteTransaction) {
|
|
guard experienceUpgrade.manifest.shouldComplete else {
|
|
return Logger.info("Skipping marking complete for experience upgrade with uniqueId: \(experienceUpgrade.uniqueId)")
|
|
}
|
|
|
|
Logger.info("Marking complete experience upgrade with uniqueId: \(experienceUpgrade.uniqueId)")
|
|
experienceUpgrade.markAsComplete(transaction: transaction.asAnyWrite)
|
|
}
|
|
|
|
public class func markAllCompleteForNewUser(transaction: GRDBWriteTransaction) {
|
|
allKnownExperienceUpgrades(transaction: transaction.asAnyRead)
|
|
.filter { $0.manifest.skipForNewUsers }
|
|
.forEach { markAsComplete(experienceUpgrade: $0, transaction: transaction) }
|
|
}
|
|
|
|
// MARK: -
|
|
|
|
/// Returns an array of all recognized ``ExperienceUpgrade``s. Contains the
|
|
/// persisted record if one exists and is applicable, and an in-memory
|
|
/// model otherwise.
|
|
private class func allKnownExperienceUpgrades(
|
|
transaction: SDSAnyReadTransaction
|
|
) -> [ExperienceUpgrade] {
|
|
var experienceUpgrades = [ExperienceUpgrade]()
|
|
var localManifestsWithoutRecords = ExperienceUpgradeManifest.wellKnownLocalUpgradeManifests
|
|
|
|
// Load any experience upgrades with persisted records...
|
|
ExperienceUpgrade.anyEnumerate(transaction: transaction) { experienceUpgrade, _ in
|
|
if case .unrecognized = experienceUpgrade.manifest {
|
|
// Ignore any no-longer-recognized records.
|
|
return
|
|
}
|
|
|
|
guard experienceUpgrade.manifest.shouldSave else {
|
|
// Ignore saved records that we no longer persist.
|
|
return
|
|
}
|
|
|
|
experienceUpgrades.append(experienceUpgrade)
|
|
localManifestsWithoutRecords.remove(experienceUpgrade.manifest)
|
|
}
|
|
|
|
// ...and instantiate new (in-memory) models for any local manifests
|
|
// without persisted records.
|
|
for localManifest in localManifestsWithoutRecords {
|
|
experienceUpgrades.append(ExperienceUpgrade.makeNew(withManifest: localManifest))
|
|
}
|
|
|
|
return experienceUpgrades.sortedByImportance()
|
|
}
|
|
}
|
|
|
|
public extension ExperienceUpgrade {
|
|
var isSnoozed: Bool {
|
|
guard
|
|
lastSnoozedTimestamp > 0,
|
|
snoozeCount > 0
|
|
else {
|
|
return false
|
|
}
|
|
|
|
// Check if enough time has passed since the last snooze date.
|
|
let timeSinceLastSnooze = -Date(timeIntervalSince1970: lastSnoozedTimestamp).timeIntervalSinceNow
|
|
return timeSinceLastSnooze <= manifest.snoozeDuration(forSnoozeCount: snoozeCount)
|
|
}
|
|
|
|
var hasPassedNumberOfDaysToShow: Bool {
|
|
daysSinceFirstViewed > manifest.numberOfDaysToShowFor
|
|
}
|
|
|
|
var daysSinceFirstViewed: Int {
|
|
guard firstViewedTimestamp > 0 else { return 0 }
|
|
|
|
let secondsSinceFirstView = -Date(timeIntervalSince1970: firstViewedTimestamp).timeIntervalSinceNow
|
|
return Int(secondsSinceFirstView / kDayInterval)
|
|
}
|
|
}
|