diff --git a/App/RecordScreen.swift b/App/RecordScreen.swift index 8821cf0b..79cb56f1 100644 --- a/App/RecordScreen.swift +++ b/App/RecordScreen.swift @@ -1253,6 +1253,12 @@ final class RecordScreenModel { if let moment { offerPro(moment) } } + /// The first Show's end (#62), from the plan as owned so a pack owner whose pack's mixer was Armed still gets it, + /// with the upgrade (Eric, #969). + static func firstShowOffer(_ offers: inout ProOffers, show: String, takeCount: Int, pro: ProStore) -> ProOfferMoment? { + offers.afterShowEnded(show: show, takeCount: takeCount, license: pro.planLicense()) + } + /// The Trial's last days between Takes (#62), from the plan as owned so a pack on the Armed family doesn't hide them /// (#961). static func trialNote(_ offers: inout ProOffers, show: String?, pro: ProStore, isRecording: Bool) -> ProOfferMoment? { @@ -1305,8 +1311,7 @@ final class RecordScreenModel { let ending = recorder.currentShow do { try sequencer.endShow() - if let ending, let moment = proOffers.afterShowEnded( - show: ending.name, takeCount: ending.takeCount, license: pro.license()) { + if let ending, let moment = Self.firstShowOffer(&proOffers, show: ending.name, takeCount: ending.takeCount, pro: pro) { offerPro(moment) } return nil diff --git a/AppTests/FirstShowOfferTests.swift b/AppTests/FirstShowOfferTests.swift new file mode 100644 index 00000000..55ecb058 --- /dev/null +++ b/AppTests/FirstShowOfferTests.swift @@ -0,0 +1,39 @@ +import Foundation +import Recording +import Testing +@testable import ShowRecorder + +/// The offer when the first Show ends (#969): it reads the plan as owned, so a pack owner whose pack's mixer was +/// Armed still gets it, with the upgrade. +@MainActor +struct FirstShowOfferTests { + func store(owning ids: [String]) -> ProStore { + let owned = ids.map { OwnedPurchase(productID: $0, purchaseDate: Date().addingTimeInterval(-86_400)) } + let store = ProStore(status: ProStatus(lastKnown: ProPurchases(owned: owned))) + store.armedFamily = { .xAir } + return store + } + + func offer(_ pro: ProStore) -> ProOfferMoment? { + var offers = ProOffers(defaults: UserDefaults(suiteName: UUID().uuidString)!) + return RecordScreenModel.firstShowOffer(&offers, show: "Friday", takeCount: 3, pro: pro) + } + + @Test func packOwnerGetsTheFirstShowOfferWithTheUpgrade() { + let pro = store(owning: [ProPurchases.packProductIDs[.xAir]!]) + #expect(offer(pro) == .firstShowEnded) + let purchases = pro.purchases + #expect(PackOffer.items( + ownsPro: purchases.ownsPro, armedFamily: .xAir, ownedPacks: purchases.ownedPacks, + boughtPacks: purchases.boughtPacks, packsOffered: PackAvailability.isAvailableInThisBuild) == [.upgrade], + "the paywall it opens offers the upgrade") + } + + @Test func proOwnerNeverGetsIt() { + #expect(offer(store(owning: [ProPurchases.proProductID])) == nil) + } + + @Test func freeUserStillGetsIt() { + #expect(offer(store(owning: [])) == .firstShowEnded) + } +} diff --git a/ShowRecorder.xcodeproj/project.pbxproj b/ShowRecorder.xcodeproj/project.pbxproj index bec6e5d1..3ad21600 100644 --- a/ShowRecorder.xcodeproj/project.pbxproj +++ b/ShowRecorder.xcodeproj/project.pbxproj @@ -30,6 +30,7 @@ 425C1B6F2EF14106616C0F7C /* DemoLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1BA48054FA4738E31732A40E /* DemoLink.swift */; }; 42E521FCCC800B2B20D0B69B /* WindowCloseGuard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8DFAA5CBF9186C8638F0BDDD /* WindowCloseGuard.swift */; }; 47525D0C9DECC739535A5E15 /* DemoAudioDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2794C7A06BF3F0B4E5F274F6 /* DemoAudioDevice.swift */; }; + 4A96580CBAF9960CBD63D216 /* FirstShowOfferTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 461EAA41996A507A52BD1445 /* FirstShowOfferTests.swift */; }; 4B1D83A876DD31D7B6E31F73 /* AppearanceStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F1B5EEDD8FA484B7416BB0B /* AppearanceStyle.swift */; }; 4B277180EC441F56D74ED665 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8F032F2B06E5F2F3AA51A95B /* Assets.xcassets */; }; 4ED0D022389613E78380D23E /* TrialSheetTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC392AB28BE7D826B3A9216D /* TrialSheetTests.swift */; }; @@ -144,6 +145,7 @@ 3ED85A0ECD05797420331099 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; 3F1B5EEDD8FA484B7416BB0B /* AppearanceStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppearanceStyle.swift; sourceTree = ""; }; 3F25297D625A2C059541D858 /* StatusStrip.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusStrip.swift; sourceTree = ""; }; + 461EAA41996A507A52BD1445 /* FirstShowOfferTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirstShowOfferTests.swift; sourceTree = ""; }; 497820F0F5EF694FC7765883 /* DriveFolderModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DriveFolderModel.swift; sourceTree = ""; }; 4AE3649927662D4F08EC25D9 /* MeterGridTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeterGridTests.swift; sourceTree = ""; }; 5E878A7AD64F581255B82A6E /* ProSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProSection.swift; sourceTree = ""; }; @@ -259,6 +261,7 @@ children = ( 8518F1A98FCD82D02B991C62 /* AppVersionTests.swift */, C8309F65F6D2135D9274A367 /* DriveFolderModelTests.swift */, + 461EAA41996A507A52BD1445 /* FirstShowOfferTests.swift */, 4AE3649927662D4F08EC25D9 /* MeterGridTests.swift */, F3D98E5C83E528C4AEB5B355 /* SupportMailTests.swift */, 9258491DEF2285144B77ED93 /* TrialNoteTests.swift */, @@ -544,6 +547,7 @@ files = ( A46EF972570A8C8B4881455D /* AppVersionTests.swift in Sources */, 01E4851C32FBDE4D3CCC11D7 /* DriveFolderModelTests.swift in Sources */, + 4A96580CBAF9960CBD63D216 /* FirstShowOfferTests.swift in Sources */, 201B434DBE445FE432B3A9FB /* MeterGridTests.swift in Sources */, DA46657B1E3BAA150CD1F749 /* SupportMailTests.swift in Sources */, 86D02F5B48C3A86B008A219F /* TrialNoteTests.swift in Sources */,