TM-SGNL-iOS/SignalServiceKit/Megaphones/ExperienceUpgradeFinder.swift
TeleMessage developers dde0620daf initial commit
2025-05-03 12:28:28 -07:00

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)
}
}