Skip to content

Commit

Permalink
Rename history to results, fix some IAP stuff (#70)
Browse files Browse the repository at this point in the history
  • Loading branch information
EvanCooper9 authored Jan 7, 2023
1 parent 9dd3703 commit 6278e96
Show file tree
Hide file tree
Showing 37 changed files with 466 additions and 225 deletions.
10 changes: 5 additions & 5 deletions Friendly Competitions Tests/Models/DeepLinkTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ final class DeepLinkTests: XCTestCase {
XCTAssertEqual(deepLink, .competition(id: "abc123"))
}

func testThatCompetitionHistoryCanBeInitialized() {
let url = URL(string: "https://friendly-competitions.app/competition/abc123/history")!
func testThatCompetitionResultsCanBeInitialized() {
let url = URL(string: "https://friendly-competitions.app/competition/abc123/results")!
let deepLink = DeepLink(from: url)
XCTAssertEqual(deepLink, .competitionHistory(id: "abc123"))
XCTAssertEqual(deepLink, .competitionResults(id: "abc123"))
}

func testThatUrlIsCorrect() {
Expand All @@ -31,8 +31,8 @@ final class DeepLinkTests: XCTestCase {
URL(string: "https://friendly-competitions.app/competition/\(#function)")!
)
XCTAssertEqual(
DeepLink.competitionHistory(id: #function).url,
URL(string: "https://friendly-competitions.app/competition/\(#function)/history")!
DeepLink.competitionResults(id: #function).url,
URL(string: "https://friendly-competitions.app/competition/\(#function)/results")!
)
}
}
66 changes: 39 additions & 27 deletions Friendly Competitions.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,16 @@
"location" : "https://github.com/EvanCooper9/ECKit",
"state" : {
"branch" : "main",
"revision" : "07c0c526cc638c112ffc87b94490dac0b34a6fbd"
"revision" : "6d2622798d5346fdbdac3a520fbb121be204ca5d"
}
},
{
"identity" : "factory",
"kind" : "remoteSourceControl",
"location" : "https://github.com/hmlongco/Factory",
"state" : {
"revision" : "8557426f3286e20b631ecdac8115242f888656e0",
"version" : "1.2.8"
"revision" : "e7a84d45dd0c2d5eff3328f979ee0bb6175c9040",
"version" : "1.3.1"
}
},
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.882",
"green" : "0.980",
"red" : "0.176"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
9 changes: 9 additions & 0 deletions Friendly Competitions/Colors.xcassets/Branded/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"provides-namespace" : true
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.247",
"green" : "0.973",
"red" : "0.698"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.365",
"green" : "0.176",
"red" : "0.961"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
15 changes: 6 additions & 9 deletions Friendly Competitions/Managers/CompetitionsManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ protocol CompetitionsManaging {
func search(_ searchText: String) -> AnyPublisher<[Competition], Error>
func search(byID competitionID: Competition.ID) -> AnyPublisher<Competition?, Error>

func history(for competitionID: Competition.ID) -> AnyPublisher<[CompetitionHistory], Error>
func results(for competitionID: Competition.ID) -> AnyPublisher<[CompetitionResult], Error>
func standings(for competitionID: Competition.ID, endingOn end: Date) -> AnyPublisher<[Competition.Standing], Error>
}

Expand Down Expand Up @@ -69,8 +69,6 @@ final class CompetitionsManager: CompetitionsManaging {
@Injected(Container.userManager) private var userManager
@LazyInjected(Container.workoutManager) private var workoutManager

private var historyCache = [Competition.ID: [Competition.Standing]]()

private var updateTask: Task<Void, Error>? {
willSet { updateTask?.cancel() }
}
Expand Down Expand Up @@ -207,20 +205,19 @@ final class CompetitionsManager: CompetitionsManaging {
}
}

func history(for competitionID: Competition.ID) -> AnyPublisher<[CompetitionHistory], Error> {
database.collection("competitions/\(competitionID)/history")
func results(for competitionID: Competition.ID) -> AnyPublisher<[CompetitionResult], Error> {
database.collection("competitions/\(competitionID)/results")
.getDocuments()
.map { $0.documents.decoded(asArrayOf: CompetitionHistory.self) }
.map { $0.documents.decoded(asArrayOf: CompetitionResult.self) }
.eraseToAnyPublisher()
}

func standings(for competitionID: Competition.ID, endingOn end: Date) -> AnyPublisher<[Competition.Standing], Error> {
// if let cachedResults = historyCache[competitionID] { return .just(cachedResults) }
// if let cachedResults = resultsCache[competitionID] { return .just(cachedResults) }
let dateString = DateFormatter.dateDashed.string(from: end)
return database.collection("competitions/\(competitionID)/history/\(dateString)/standings")
return database.collection("competitions/\(competitionID)/results/\(dateString)/standings")
.getDocuments()
.map { $0.documents.compactMap { try? $0.data(as: Competition.Standing.self) } }
.handleEvents(withUnretained: self, receiveOutput: { $0.historyCache[competitionID] = $1 })
.eraseToAnyPublisher()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"settings" : {
"_applicationInternalID" : "1586333967",
"_developerTeamID" : "HP22MNWU5C",
"_lastSynchronizedDate" : 694738914.27802205
"_lastSynchronizedDate" : 694751686.757725
},
"subscriptionGroups" : [
{
Expand All @@ -28,13 +28,13 @@
],
"displayPrice" : "12.99",
"familyShareable" : false,
"groupNumber" : 3,
"groupNumber" : 1,
"internalID" : "6445321415",
"introductoryOffer" : null,
"localizations" : [
{
"description" : "Access premium features for one year",
"displayName" : "Premium Annually",
"displayName" : "Annually",
"locale" : "en_CA"
}
],
Expand All @@ -53,7 +53,7 @@
],
"displayPrice" : "0.99",
"familyShareable" : false,
"groupNumber" : 1,
"groupNumber" : 3,
"internalID" : "6445321260",
"introductoryOffer" : null,
"localizations" : [
Expand Down Expand Up @@ -84,7 +84,7 @@
"localizations" : [
{
"description" : "Access premium features for six months",
"displayName" : "Premium Semi-Annually",
"displayName" : "Semi-Annually",
"locale" : "en_CA"
}
],
Expand Down
40 changes: 24 additions & 16 deletions Friendly Competitions/Managers/StoreKit/StoreKitManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ protocol StoreKitManaging {
var products: AnyPublisher<[FriendlyCompetitionsProduct], Never> { get }
var purchases: AnyPublisher<[FriendlyCompetitionsProduct], Never> { get }
func purchase(_ product: FriendlyCompetitionsProduct) -> AnyPublisher<Void, Error>
func refreshPurchasedProducts() -> AnyPublisher<Void, Error>
}

extension StoreKitManaging {
Expand All @@ -33,6 +34,8 @@ final class StoreKitManager: StoreKitManaging {

// MARK: - Private Properties

private var storeKitProducts = Set<Product>()

@Injected(Container.analyticsManager) private var analyticsManager
@Injected(Container.database) private var database
@Injected(Container.userManager) private var userManager
Expand All @@ -53,15 +56,8 @@ final class StoreKitManager: StoreKitManaging {
}
listenForTransactions()

database.collection("products")
.getDocuments()
.map(\.documents)
.mapMany(\.documentID)
.sink(withUnretained: self) { strongSelf, productIDs in
Task {
try await strongSelf.refreshProducts(with: productIDs)
}
}
refreshPurchasedProducts()
.sink()
.store(in: &cancellables)
}

Expand Down Expand Up @@ -89,9 +85,11 @@ final class StoreKitManager: StoreKitManaging {
.flatMapAsync { [weak self] userAppStoreID in
guard let strongSelf = self else { return }

let result = try await Product.products(for: [product.id])
.first?
.purchase(options: [.appAccountToken(userAppStoreID)])
var skProduct = strongSelf.storeKitProducts.first(where: { $0.id == product.id })
if skProduct == nil {
skProduct = try await Product.products(for: [product.id]).first
}
let result = try await skProduct?.purchase(options: [.appAccountToken(userAppStoreID)])

switch result {
case .success(let verificationResult):
Expand Down Expand Up @@ -121,15 +119,25 @@ final class StoreKitManager: StoreKitManaging {
}
}

func refreshPurchasedProducts() -> AnyPublisher<Void, Error> {
database.collection("products")
.getDocuments()
.flatMapAsync { [weak self] result in
let productIDs = result.documents.map(\.documentID)
try await self?.refreshProducts(with: productIDs)
}
.eraseToAnyPublisher()
}

// MARK: - Private Methods

private func refreshProducts(with productIDs: [String]) async throws {
let products = try await Product
.products(for: productIDs)
.sorted(by: \.price)
.map(FriendlyCompetitionsProduct.init)

productsSubject.send(products)
products.forEach { storeKitProducts.insert($0) }
productsSubject.send(products.map(FriendlyCompetitionsProduct.init))
}

private func refreshPurchasedProducts() async throws {
Expand All @@ -155,7 +163,7 @@ final class StoreKitManager: StoreKitManaging {
}
}

private func handle(updatedTransaction verificationResult: VerificationResult<Transaction>) {
private func handle(updatedTransaction verificationResult: VerificationResult<StoreKit.Transaction>) {
// Ignore unverified transactions.
guard case .verified(let transaction) = verificationResult,
let product = productsSubject.value.first(where: { $0.id == transaction.productID })
Expand All @@ -177,7 +185,7 @@ final class StoreKitManager: StoreKitManaging {
}
}

private func logUnverifiedTransaction(_ unverifiedTransaction: Transaction, _ verificationError: Error) {
private func logUnverifiedTransaction(_ unverifiedTransaction: StoreKit.Transaction, _ verificationError: Error) {
let crashlytics = Crashlytics.crashlytics()
crashlytics.record(exceptionModel: .init(name: "Unverified transaction", reason: unverifiedTransaction.productID))
crashlytics.record(error: verificationError)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

struct CompetitionHistory: Codable, Identifiable {
struct CompetitionResult: Codable, Identifiable {
let id: String
@PostDecoded<DateToMidnight, Date> var start: Date
@PostDecoded<DateToMidnight, Date> var end: Date
Expand Down
12 changes: 6 additions & 6 deletions Friendly Competitions/Models/Deep Link/DeepLink.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ enum DeepLink: Equatable {

case user(id: User.ID)
case competition(id: Competition.ID)
case competitionHistory(id: Competition.ID)
case competitionResults(id: Competition.ID)

init?(from url: URL) {
let path = url.path
Expand All @@ -19,8 +19,8 @@ enum DeepLink: Equatable {
return
} else if path.hasPrefix("/" + Constants.competition) {
let competitionID = url.pathComponents[2]
if path.hasSuffix("history") {
self = .competitionHistory(id: competitionID)
if path.hasSuffix("results") {
self = .competitionResults(id: competitionID)
return
} else {
self = .competition(id: competitionID)
Expand All @@ -40,11 +40,11 @@ enum DeepLink: Equatable {
return Constants.baseURL
.appendingPathComponent(Constants.competition)
.appendingPathComponent(id)
case .competitionHistory(let id):
case .competitionResults(let id):
return Constants.baseURL
.appendingPathComponent(Constants.competition)
.appendingPathComponent(id)
.appendingPathComponent("history")
.appendingPathComponent("results")
}
}
}
Expand All @@ -58,7 +58,7 @@ extension DeepLink: Sharable {
text = "Add me in Friendly Competitions!"
case .competition:
text = "Compete against me in Friendly Competitions!"
case .competitionHistory:
case .competitionResults:
return []
}
return [text, url.absoluteString]
Expand Down
12 changes: 10 additions & 2 deletions Friendly Competitions/Preview Content/Helpers/PreviewHelper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ fileprivate enum Dependencies {
competitionsManager.pendingParticipants = .just([:])
competitionsManager.appOwnedCompetitions = .just([.mockPublic])
competitionsManager.searchReturnValue = .just([.mockPublic, .mock])
competitionsManager.historyForReturnValue = .just([])
competitionsManager.resultsForReturnValue = .just([])
competitionsManager.standingsForEndingOnReturnValue = .just([])

friendsManager.friends = .just([])
Expand All @@ -54,7 +54,15 @@ fileprivate enum Dependencies {

storageManager.dataForReturnValue = .just(.init())

storeKitManager.products = .just([])
let products: [FriendlyCompetitionsProduct] = [
.init(id: "1", price: "$0.99/month", title: "Monthly", description: "Access premium features for one month"),
.init(id: "2", price: "$1.99/six months", title: "Semi-Annually", description: "Access premium features for six months"),
.init(id: "3", price: "$2.99/year", title: "Yearly", description: "Access premium features for one year")
]
storeKitManager.products = .just(products)
storeKitManager.purchases = .just([])
storeKitManager.purchaseReturnValue = .just(())
storeKitManager.refreshPurchasedProductsReturnValue = .just(())

userManager.user = .evan
userManager.userPublisher = .just(.evan)
Expand Down
Loading

0 comments on commit 6278e96

Please sign in to comment.