De-SDS-ify ExperienceUpgrade
This commit is contained in:
parent
c57f731c67
commit
102b164f89
@ -2897,6 +2897,7 @@
|
||||
D9791BC42EAADF010016AA5A /* HTTPResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9791BC32EAADEFD0016AA5A /* HTTPResponse.swift */; };
|
||||
D97992A12D9E55F20080A4F5 /* CurrencyFormatterTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = D97992A02D9E55E10080A4F5 /* CurrencyFormatterTest.swift */; };
|
||||
D97992A32D9E55FB0080A4F5 /* CurrencyFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = D97992A22D9E55F80080A4F5 /* CurrencyFormatter.swift */; };
|
||||
D97992AC2FC147C5002E79F3 /* ExperienceUpgradeStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = D97992AB2FC147C2002E79F3 /* ExperienceUpgradeStore.swift */; };
|
||||
D979CC262AD3933B006AAC49 /* IndividualCallRecordManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D979CC1F2AD3933B006AAC49 /* IndividualCallRecordManager.swift */; };
|
||||
D979CC292AD3933B006AAC49 /* OutgoingCallEventSyncMessageManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D979CC222AD3933B006AAC49 /* OutgoingCallEventSyncMessageManager.swift */; };
|
||||
D979CC2B2AD3933B006AAC49 /* InteractionStore+CallRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = D979CC242AD3933B006AAC49 /* InteractionStore+CallRecord.swift */; };
|
||||
@ -7183,6 +7184,7 @@
|
||||
D9791BC32EAADEFD0016AA5A /* HTTPResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HTTPResponse.swift; sourceTree = "<group>"; };
|
||||
D97992A02D9E55E10080A4F5 /* CurrencyFormatterTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrencyFormatterTest.swift; sourceTree = "<group>"; };
|
||||
D97992A22D9E55F80080A4F5 /* CurrencyFormatter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrencyFormatter.swift; sourceTree = "<group>"; };
|
||||
D97992AB2FC147C2002E79F3 /* ExperienceUpgradeStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExperienceUpgradeStore.swift; sourceTree = "<group>"; };
|
||||
D979CC1F2AD3933B006AAC49 /* IndividualCallRecordManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IndividualCallRecordManager.swift; sourceTree = "<group>"; };
|
||||
D979CC202AD3933B006AAC49 /* IncomingCallEventSyncMessageManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IncomingCallEventSyncMessageManager.swift; sourceTree = "<group>"; };
|
||||
D979CC222AD3933B006AAC49 /* OutgoingCallEventSyncMessageManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OutgoingCallEventSyncMessageManager.swift; sourceTree = "<group>"; };
|
||||
@ -13327,6 +13329,7 @@
|
||||
D9C7CEB328EB8495001E87B6 /* ExperienceUpgrade.swift */,
|
||||
F9C5CB5B289453B200548EEE /* ExperienceUpgradeFinder.swift */,
|
||||
D9C7CECA28EBC09C001E87B6 /* ExperienceUpgradeManifest.swift */,
|
||||
D97992AB2FC147C2002E79F3 /* ExperienceUpgradeStore.swift */,
|
||||
040506FB2F7FE3D50078B769 /* RemoteAnnouncementModel.swift */,
|
||||
D98DD85E28EE53B00089333E /* RemoteMegaphoneModel.swift */,
|
||||
040506FF2F8049910078B769 /* RemoteReleaseNotesService.swift */,
|
||||
@ -19232,6 +19235,7 @@
|
||||
D9C7CEB428EB8495001E87B6 /* ExperienceUpgrade.swift in Sources */,
|
||||
F9C5CE2D289453B400548EEE /* ExperienceUpgradeFinder.swift in Sources */,
|
||||
D9C7CECB28EBC09C001E87B6 /* ExperienceUpgradeManifest.swift in Sources */,
|
||||
D97992AC2FC147C5002E79F3 /* ExperienceUpgradeStore.swift in Sources */,
|
||||
D98BC5332EE387A30052A81F /* ExpirationJob.swift in Sources */,
|
||||
C1FB9B752B16498C00D51A3B /* ExternalPendingDonationStore.swift in Sources */,
|
||||
F9C5CE57289453B400548EEE /* Factories.swift in Sources */,
|
||||
|
||||
@ -8,20 +8,36 @@ public import SignalServiceKit
|
||||
|
||||
/// Handles fetching and parsing remote megaphones.
|
||||
public class RemoteMegaphoneFetcher: RemoteReleaseNotesFetcher<RemoteMegaphoneModel.Manifest, RemoteMegaphoneModel.Translation> {
|
||||
private let experienceUpgradeStore: ExperienceUpgradeStore
|
||||
|
||||
override init(
|
||||
db: DB,
|
||||
remoteReleaseNotesService: any RemoteReleaseNotesServiceProtocol,
|
||||
) {
|
||||
self.experienceUpgradeStore = ExperienceUpgradeStore()
|
||||
|
||||
super.init(
|
||||
db: db,
|
||||
remoteReleaseNotesService: remoteReleaseNotesService,
|
||||
)
|
||||
}
|
||||
|
||||
/// Update our local persisted megaphone state with freshly-fetched
|
||||
/// megaphones from the service. Updates existing megaphones if present,
|
||||
/// and creates new ones if necessary. Removes any locally-persisted
|
||||
/// megaphones that no longer exist on the service.
|
||||
override func updatePersistedData(
|
||||
withFetchedData fetchedTranslations: [(RemoteMegaphoneModel.Manifest, RemoteMegaphoneModel.Translation)],
|
||||
transaction: DBWriteTransaction,
|
||||
transaction tx: DBWriteTransaction,
|
||||
) {
|
||||
// Get the current remote megaphones.
|
||||
var localRemoteMegaphones: [String: ExperienceUpgrade] = [:]
|
||||
ExperienceUpgrade.anyEnumerate(transaction: transaction) { upgrade, _ in
|
||||
if case .remoteMegaphone = upgrade.manifest {
|
||||
localRemoteMegaphones[upgrade.uniqueId] = upgrade
|
||||
// Get any persisted ExperienceUpgrades for the remote megaphones.
|
||||
var experienceUpgradesByMegaphoneId: [String: ExperienceUpgrade] = [:]
|
||||
experienceUpgradeStore.enumerateExperienceUpgrades(tx: tx) { experienceUpgrade in
|
||||
guard case .remoteMegaphone(let model) = experienceUpgrade.manifest else {
|
||||
return
|
||||
}
|
||||
|
||||
experienceUpgradesByMegaphoneId[model.manifest.id] = experienceUpgrade
|
||||
}
|
||||
|
||||
// Insert all megaphones we got from the service. If we already have a
|
||||
@ -30,23 +46,28 @@ public class RemoteMegaphoneFetcher: RemoteReleaseNotesFetcher<RemoteMegaphoneMo
|
||||
// For example, if the user's locale has changed we may have updated
|
||||
// translations.
|
||||
for (manifest, translation) in fetchedTranslations {
|
||||
let serviceMegaphone = RemoteMegaphoneModel(manifest: manifest, translation: translation)
|
||||
if let existingLocalMegaphone = localRemoteMegaphones[serviceMegaphone.id] {
|
||||
existingLocalMegaphone.updateManifestRemoteMegaphone(withRefetchedMegaphone: serviceMegaphone)
|
||||
existingLocalMegaphone.anyUpsert(transaction: transaction)
|
||||
|
||||
localRemoteMegaphones.removeValue(forKey: serviceMegaphone.id)
|
||||
let remoteMegaphoneModel = RemoteMegaphoneModel(manifest: manifest, translation: translation)
|
||||
let experienceUpgrade: ExperienceUpgrade
|
||||
if let persisted = experienceUpgradesByMegaphoneId.removeValue(forKey: manifest.id) {
|
||||
experienceUpgrade = persisted
|
||||
} else {
|
||||
ExperienceUpgrade
|
||||
.makeNew(withManifest: .remoteMegaphone(megaphone: serviceMegaphone))
|
||||
.anyInsert(transaction: transaction)
|
||||
experienceUpgrade = .makeNew(withManifest: .remoteMegaphone(megaphone: remoteMegaphoneModel))
|
||||
}
|
||||
|
||||
experienceUpgradeStore.upsertRemoteMegaphone(
|
||||
experienceUpgrade: experienceUpgrade,
|
||||
newRemoteMegaphoneModel: remoteMegaphoneModel,
|
||||
tx: tx,
|
||||
)
|
||||
}
|
||||
|
||||
// Remove records for any remaining local megaphones, which are no
|
||||
// longer on the service.
|
||||
for (_, experienceUpgradeToRemove) in localRemoteMegaphones {
|
||||
experienceUpgradeToRemove.anyRemove(transaction: transaction)
|
||||
for (_, experienceUpgradeToRemove) in experienceUpgradesByMegaphoneId {
|
||||
experienceUpgradeStore.remove(
|
||||
experienceUpgrade: experienceUpgradeToRemove,
|
||||
tx: tx,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -12,6 +12,7 @@ import Testing
|
||||
@MainActor
|
||||
struct RemoteReleaseNotesFetchingManagerTests {
|
||||
private let db = InMemoryDB()
|
||||
private let experienceUpgradeStore = ExperienceUpgradeStore()
|
||||
private let remoteReleaseNotesFetchingManager: RemoteReleaseNotesFetchingManager
|
||||
|
||||
init() {
|
||||
@ -26,7 +27,7 @@ struct RemoteReleaseNotesFetchingManagerTests {
|
||||
try await remoteReleaseNotesFetchingManager.syncRemoteReleaseNotes()
|
||||
|
||||
db.read { tx in
|
||||
ExperienceUpgrade.anyEnumerate(transaction: tx) { upgrade, _ in
|
||||
experienceUpgradeStore.enumerateExperienceUpgrades(tx: tx) { upgrade in
|
||||
switch upgrade.manifest {
|
||||
case .remoteMegaphone(let megaphone):
|
||||
#expect(megaphone.translation.title == "Donate Today")
|
||||
|
||||
@ -6,7 +6,9 @@
|
||||
import Foundation
|
||||
public import GRDB
|
||||
|
||||
public class ExperienceUpgrade: SDSCodableModel, Decodable {
|
||||
public class ExperienceUpgrade: Codable, FetchableRecord, PersistableRecord {
|
||||
public typealias IDType = Int64
|
||||
|
||||
public static let databaseTableName = "model_ExperienceUpgrade"
|
||||
private static var recordType: SDSRecordType { .experienceUpgrade }
|
||||
|
||||
@ -22,25 +24,26 @@ public class ExperienceUpgrade: SDSCodableModel, Decodable {
|
||||
case manifest
|
||||
}
|
||||
|
||||
public var id: RowId?
|
||||
public var id: IDType?
|
||||
|
||||
public var uniqueId: String {
|
||||
manifest.uniqueId
|
||||
}
|
||||
|
||||
/// Timestamp when this upgrade was first viewed.
|
||||
public private(set) var firstViewedTimestamp: TimeInterval
|
||||
public var firstViewedTimestamp: TimeInterval
|
||||
|
||||
/// Timestamp when this upgrade was last snoozed.
|
||||
public internal(set) var lastSnoozedTimestamp: TimeInterval
|
||||
public var lastSnoozedTimestamp: TimeInterval
|
||||
|
||||
/// Number of times this upgrade has been snoozed.
|
||||
public internal(set) var snoozeCount: UInt
|
||||
public var snoozeCount: UInt
|
||||
|
||||
/// Whether this upgrade should be considered fully complete.
|
||||
public private(set) var isComplete: Bool
|
||||
public var isComplete: Bool
|
||||
|
||||
/// Identifies and holds metadata about this ``ExperienceUpgrade``.
|
||||
public private(set) var manifest: ExperienceUpgradeManifest
|
||||
public var manifest: ExperienceUpgradeManifest
|
||||
|
||||
private init(manifest: ExperienceUpgradeManifest) {
|
||||
self.firstViewedTimestamp = 0
|
||||
@ -55,6 +58,21 @@ public class ExperienceUpgrade: SDSCodableModel, Decodable {
|
||||
ExperienceUpgrade(manifest: manifest)
|
||||
}
|
||||
|
||||
// MARK: - PersistableRecord
|
||||
|
||||
public func didInsert(with rowID: Int64, for column: String?) {
|
||||
id = rowID
|
||||
}
|
||||
|
||||
public static let persistenceConflictPolicy: PersistenceConflictPolicy = PersistenceConflictPolicy(
|
||||
insert: .replace,
|
||||
update: .replace,
|
||||
)
|
||||
|
||||
public func upsert(tx: DBWriteTransaction) throws {
|
||||
try self.insert(tx.database)
|
||||
}
|
||||
|
||||
// MARK: - Codable
|
||||
|
||||
public required init(from decoder: Decoder) throws {
|
||||
@ -63,7 +81,7 @@ public class ExperienceUpgrade: SDSCodableModel, Decodable {
|
||||
let decodedRecordType = try container.decode(Int64.self, forKey: .recordType)
|
||||
owsAssertDebug(decodedRecordType == Self.recordType.rawValue, "Unexpectedly decoded record with wrong type.")
|
||||
|
||||
id = try container.decodeIfPresent(RowId.self, forKey: .id)
|
||||
id = try container.decodeIfPresent(IDType.self, forKey: .id)
|
||||
|
||||
firstViewedTimestamp = try container.decode(TimeInterval.self, forKey: .firstViewedTimestamp)
|
||||
lastSnoozedTimestamp = try container.decode(TimeInterval.self, forKey: .lastSnoozedTimestamp)
|
||||
@ -131,85 +149,4 @@ public class ExperienceUpgrade: SDSCodableModel, Decodable {
|
||||
|
||||
return Int(clamping: daysSinceFirstView) > manifest.numberOfDaysToShowFor
|
||||
}
|
||||
|
||||
// MARK: - Removal
|
||||
|
||||
public func anyDidRemove(transaction: DBWriteTransaction) {
|
||||
switch manifest {
|
||||
case
|
||||
.introducingPins,
|
||||
.notificationPermissionReminder,
|
||||
.newLinkedDeviceNotification,
|
||||
.createUsernameReminder,
|
||||
.inactiveLinkedDeviceReminder,
|
||||
.inactivePrimaryDeviceReminder,
|
||||
.pinReminder,
|
||||
.contactPermissionReminder,
|
||||
.backupKeyReminder,
|
||||
.enableBackupsReminder,
|
||||
.haveEnabledBackupsNotification,
|
||||
.unrecognized:
|
||||
return
|
||||
case .remoteMegaphone(let megaphone):
|
||||
guard megaphone.translation.hasImage else {
|
||||
return
|
||||
}
|
||||
|
||||
do {
|
||||
let imageLocalUrl = RemoteMegaphoneModel.imagesDirectory.appendingPathComponent(megaphone.translation.imageLocalRelativePath)
|
||||
try FileManager.default.removeItem(at: imageLocalUrl)
|
||||
} catch let error {
|
||||
owsFailDebug("Failed to remove image file for removed remote megaphone with ID \(megaphone.id)! \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Mark as <state>
|
||||
|
||||
public func markAsSnoozed(transaction: DBWriteTransaction) {
|
||||
upsert(withTransaction: transaction) { upgrade in
|
||||
upgrade.lastSnoozedTimestamp = Date().timeIntervalSince1970
|
||||
upgrade.snoozeCount += 1
|
||||
}
|
||||
}
|
||||
|
||||
public func markAsComplete(transaction: DBWriteTransaction) {
|
||||
upsert(withTransaction: transaction) { $0.isComplete = true }
|
||||
}
|
||||
|
||||
public func markAsViewed(transaction: DBWriteTransaction) {
|
||||
upsert(withTransaction: transaction) { upgrade in
|
||||
guard upgrade.firstViewedTimestamp == 0 else { return }
|
||||
upgrade.firstViewedTimestamp = Date().timeIntervalSince1970
|
||||
}
|
||||
}
|
||||
|
||||
/// If an upgrade is already persisted with our `uniqueId`, performs `block`
|
||||
/// on it and updates. Otherwise, performs `block` on ourself and inserts
|
||||
/// ourself. Skips calling `block` if this upgrade should not be saved.
|
||||
private func upsert(withTransaction transaction: DBWriteTransaction, inBlock block: (ExperienceUpgrade) -> Void) {
|
||||
guard manifest.shouldSave else {
|
||||
return
|
||||
}
|
||||
|
||||
let experienceToUpgrade = ExperienceUpgrade.anyFetch(uniqueId: uniqueId, transaction: transaction) ?? self
|
||||
block(experienceToUpgrade)
|
||||
experienceToUpgrade.anyUpsert(transaction: transaction)
|
||||
}
|
||||
|
||||
// MARK: - Update remote megaphone info
|
||||
|
||||
/// Updates a subset of properties on the existing manifest with the given
|
||||
/// re-fetched megaphone. Does nothing if the given megaphone does not
|
||||
/// match the existing.
|
||||
public func updateManifestRemoteMegaphone(withRefetchedMegaphone refetchedMegaphone: RemoteMegaphoneModel) {
|
||||
guard case .remoteMegaphone(var megaphone) = manifest else {
|
||||
owsFailDebug("Attempting to update remote megaphone, but upgrade is not a remote megaphone: \(manifest)")
|
||||
return
|
||||
}
|
||||
|
||||
megaphone.update(withRefetched: refetchedMegaphone)
|
||||
|
||||
manifest = .remoteMegaphone(megaphone: megaphone)
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,34 +9,23 @@ public class ExperienceUpgradeFinder {
|
||||
|
||||
// MARK: -
|
||||
|
||||
public class func markAsViewed(experienceUpgrade: ExperienceUpgrade, transaction: DBWriteTransaction) {
|
||||
Logger.info("marking experience upgrade as seen \(experienceUpgrade.uniqueId)")
|
||||
experienceUpgrade.markAsViewed(transaction: transaction)
|
||||
public class func markAsViewed(experienceUpgrade: ExperienceUpgrade, transaction tx: DBWriteTransaction) {
|
||||
ExperienceUpgradeStore().markAsViewed(experienceUpgrade: experienceUpgrade, tx: tx)
|
||||
}
|
||||
|
||||
public class func markAsSnoozed(experienceUpgrade: ExperienceUpgrade, transaction: DBWriteTransaction) {
|
||||
Logger.info("marking experience upgrade as snoozed \(experienceUpgrade.uniqueId)")
|
||||
|
||||
experienceUpgrade.markAsSnoozed(transaction: transaction)
|
||||
public class func markAsSnoozed(experienceUpgrade: ExperienceUpgrade, transaction tx: DBWriteTransaction) {
|
||||
ExperienceUpgradeStore().markAsSnoozed(experienceUpgrade: experienceUpgrade, tx: tx)
|
||||
}
|
||||
|
||||
public class func markAsComplete(
|
||||
experienceUpgradeManifest manifest: ExperienceUpgradeManifest,
|
||||
transaction: DBWriteTransaction,
|
||||
experienceUpgradeManifest: ExperienceUpgradeManifest,
|
||||
transaction tx: DBWriteTransaction,
|
||||
) {
|
||||
markAsComplete(
|
||||
experienceUpgrade: ExperienceUpgrade.makeNew(withManifest: manifest),
|
||||
transaction: transaction,
|
||||
)
|
||||
markAsComplete(experienceUpgrade: .makeNew(withManifest: experienceUpgradeManifest), transaction: tx)
|
||||
}
|
||||
|
||||
public class func markAsComplete(experienceUpgrade: ExperienceUpgrade, transaction: DBWriteTransaction) {
|
||||
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)
|
||||
public class func markAsComplete(experienceUpgrade: ExperienceUpgrade, transaction tx: DBWriteTransaction) {
|
||||
ExperienceUpgradeStore().markAsComplete(experienceUpgrade: experienceUpgrade, tx: tx)
|
||||
}
|
||||
|
||||
public class func markAllCompleteForNewUser(transaction: DBWriteTransaction) {
|
||||
@ -51,13 +40,13 @@ public class ExperienceUpgradeFinder {
|
||||
/// persisted record if one exists and is applicable, and an in-memory
|
||||
/// model otherwise.
|
||||
public class func allKnownExperienceUpgrades(
|
||||
transaction: DBReadTransaction,
|
||||
transaction tx: DBReadTransaction,
|
||||
) -> [ExperienceUpgrade] {
|
||||
var experienceUpgrades = [ExperienceUpgrade]()
|
||||
var localManifestsWithoutRecords = ExperienceUpgradeManifest.wellKnownLocalUpgradeManifests
|
||||
|
||||
// Load any experience upgrades with persisted records...
|
||||
ExperienceUpgrade.anyEnumerate(transaction: transaction) { experienceUpgrade, _ in
|
||||
ExperienceUpgradeStore().enumerateExperienceUpgrades(tx: tx) { experienceUpgrade in
|
||||
if case .unrecognized = experienceUpgrade.manifest {
|
||||
// Ignore any no-longer-recognized records.
|
||||
return
|
||||
|
||||
126
SignalServiceKit/Megaphones/ExperienceUpgradeStore.swift
Normal file
126
SignalServiceKit/Megaphones/ExperienceUpgradeStore.swift
Normal file
@ -0,0 +1,126 @@
|
||||
//
|
||||
// Copyright 2026 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
//
|
||||
|
||||
public struct ExperienceUpgradeStore {
|
||||
|
||||
public init() {}
|
||||
|
||||
// MARK: -
|
||||
|
||||
public func markAsSnoozed(experienceUpgrade: ExperienceUpgrade, tx: DBWriteTransaction) {
|
||||
Logger.info("Marking snoozed: \(experienceUpgrade.uniqueId)")
|
||||
|
||||
experienceUpgrade.lastSnoozedTimestamp = Date().timeIntervalSince1970
|
||||
experienceUpgrade.snoozeCount += 1
|
||||
upsert(experienceUpgrade: experienceUpgrade, tx: tx)
|
||||
}
|
||||
|
||||
public func markAsComplete(experienceUpgrade: ExperienceUpgrade, tx: DBWriteTransaction) {
|
||||
guard experienceUpgrade.manifest.shouldComplete else {
|
||||
Logger.info("Skipping marking complete: \(experienceUpgrade.uniqueId)")
|
||||
return
|
||||
}
|
||||
|
||||
Logger.info("Marking complete: \(experienceUpgrade.uniqueId)")
|
||||
|
||||
experienceUpgrade.isComplete = true
|
||||
upsert(experienceUpgrade: experienceUpgrade, tx: tx)
|
||||
}
|
||||
|
||||
public func markAsViewed(experienceUpgrade: ExperienceUpgrade, tx: DBWriteTransaction) {
|
||||
guard experienceUpgrade.firstViewedTimestamp == 0 else {
|
||||
Logger.info("Already marked viewed, skipping: \(experienceUpgrade.uniqueId)")
|
||||
return
|
||||
}
|
||||
|
||||
Logger.info("Marking first viewed: \(experienceUpgrade.uniqueId)")
|
||||
|
||||
experienceUpgrade.firstViewedTimestamp = Date().timeIntervalSince1970
|
||||
upsert(experienceUpgrade: experienceUpgrade, tx: tx)
|
||||
}
|
||||
|
||||
/// Updates a subset of properties on the existing manifest with the given
|
||||
/// re-fetched megaphone. Does nothing if the given megaphone does not
|
||||
/// match the existing.
|
||||
public func upsertRemoteMegaphone(
|
||||
experienceUpgrade: ExperienceUpgrade,
|
||||
newRemoteMegaphoneModel: RemoteMegaphoneModel,
|
||||
tx: DBWriteTransaction,
|
||||
) {
|
||||
guard
|
||||
case .remoteMegaphone(var remoteMegaphoneModel) = experienceUpgrade.manifest
|
||||
else {
|
||||
owsFailDebug("Attempting to update remote megaphone, but upgrade is not a remote megaphone! \(experienceUpgrade.uniqueId)")
|
||||
return
|
||||
}
|
||||
|
||||
remoteMegaphoneModel.updateSelectively(newRemoteMegaphoneModel: newRemoteMegaphoneModel)
|
||||
|
||||
experienceUpgrade.manifest = .remoteMegaphone(megaphone: remoteMegaphoneModel)
|
||||
upsert(experienceUpgrade: experienceUpgrade, tx: tx)
|
||||
}
|
||||
|
||||
private func upsert(experienceUpgrade: ExperienceUpgrade, tx: DBWriteTransaction) {
|
||||
guard experienceUpgrade.manifest.shouldSave else {
|
||||
return
|
||||
}
|
||||
|
||||
failIfThrows {
|
||||
try experienceUpgrade.upsert(tx: tx)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
public func enumerateExperienceUpgrades(
|
||||
tx: DBReadTransaction,
|
||||
block: (ExperienceUpgrade) -> Void,
|
||||
) {
|
||||
var cursor = FailIfThrowsRecordCursor {
|
||||
try ExperienceUpgrade.fetchCursor(tx.database)
|
||||
}
|
||||
|
||||
while let upgrade = cursor.next() {
|
||||
block(upgrade)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
public func remove(experienceUpgrade: ExperienceUpgrade, tx: DBWriteTransaction) {
|
||||
failIfThrows {
|
||||
try experienceUpgrade.delete(tx.database)
|
||||
}
|
||||
|
||||
switch experienceUpgrade.manifest {
|
||||
case .introducingPins,
|
||||
.notificationPermissionReminder,
|
||||
.newLinkedDeviceNotification,
|
||||
.createUsernameReminder,
|
||||
.inactiveLinkedDeviceReminder,
|
||||
.inactivePrimaryDeviceReminder,
|
||||
.pinReminder,
|
||||
.contactPermissionReminder,
|
||||
.backupKeyReminder,
|
||||
.enableBackupsReminder,
|
||||
.haveEnabledBackupsNotification,
|
||||
.unrecognized:
|
||||
return
|
||||
case .remoteMegaphone(let megaphone):
|
||||
guard megaphone.translation.hasImage else {
|
||||
return
|
||||
}
|
||||
|
||||
do {
|
||||
let imageLocalUrl = RemoteMegaphoneModel.imagesDirectory
|
||||
.appendingPathComponent(megaphone.translation.imageLocalRelativePath)
|
||||
|
||||
try FileManager.default.removeItem(at: imageLocalUrl)
|
||||
} catch let error {
|
||||
owsFailDebug("Failed to remove image file for removed remote megaphone with ID \(megaphone.id)! \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -36,7 +36,7 @@ public struct RemoteMegaphoneModel: Codable {
|
||||
/// been fetched and cached for this megaphone it is immutable - if this
|
||||
/// changes in the future, ensure that previously-fetched images are handled
|
||||
/// appropriately.
|
||||
mutating func update(withRefetched newMegaphone: RemoteMegaphoneModel) {
|
||||
mutating func updateSelectively(newRemoteMegaphoneModel newMegaphone: RemoteMegaphoneModel) {
|
||||
guard id == newMegaphone.id else {
|
||||
owsFailDebug("Attempting to update remote megaphone, but IDs do not match! Current: \(id), new: \(newMegaphone.id)")
|
||||
return
|
||||
|
||||
Loading…
Reference in New Issue
Block a user