Skip to content

Commit

Permalink
Compute competition standings only when viewing them & reduce billing (
Browse files Browse the repository at this point in the history
  • Loading branch information
EvanCooper9 authored Jan 20, 2023
1 parent 5bd0f72 commit 3ee4347
Show file tree
Hide file tree
Showing 39 changed files with 789 additions and 375 deletions.
22 changes: 18 additions & 4 deletions Friendly Competitions.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,6 @@
ED7881AD2850F6DF00C7F6CB /* SignUpError.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED7881AC2850F6DF00C7F6CB /* SignUpError.swift */; };
ED7881B02850F71E00C7F6CB /* AnalyticsEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED7881AF2850F71E00C7F6CB /* AnalyticsEvent.swift */; };
ED8C324729118DC400339988 /* VerifyEmailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED8C324629118DC400339988 /* VerifyEmailView.swift */; };
ED8C324929118E5500339988 /* FriendlyCompetitionsAppModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED8C324829118E5500339988 /* FriendlyCompetitionsAppModel.swift */; };
ED8C324C2911BFD300339988 /* ECKit in Frameworks */ = {isa = PBXBuildFile; productRef = ED8C324B2911BFD300339988 /* ECKit */; };
ED8C324E2911BFD300339988 /* ECKit+Firebase in Frameworks */ = {isa = PBXBuildFile; productRef = ED8C324D2911BFD300339988 /* ECKit+Firebase */; };
ED8D05F7295F5DA1002B3B3A /* CompetitionResultsDateRangeSelector.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED8D05F6295F5DA1002B3B3A /* CompetitionResultsDateRangeSelector.swift */; };
Expand All @@ -156,6 +155,7 @@
ED901B712802618700FE619E /* NewCompetitionViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED901B702802618700FE619E /* NewCompetitionViewModel.swift */; };
ED901B742802649200FE619E /* VerifyEmailViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED901B732802649200FE619E /* VerifyEmailViewModel.swift */; };
ED901B76280265DB00FE619E /* SignInViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED901B75280265DB00FE619E /* SignInViewModel.swift */; };
ED97FCA5297B238B00597A16 /* RootTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED97FCA4297B238B00597A16 /* RootTab.swift */; };
EDA035B829173F140091E7A6 /* ArrayBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDA035B729173F140091E7A6 /* ArrayBuilder.swift */; };
EDA035BB2917FE190091E7A6 /* NotificationName+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDA035BA2917FE190091E7A6 /* NotificationName+Extensions.swift */; };
EDA035BE2917FFF90091E7A6 /* Dictionary+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDA035BD2917FFF90091E7A6 /* Dictionary+Extensions.swift */; };
Expand All @@ -164,6 +164,9 @@
EDA352902836EFB600390585 /* UserViewAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDA3528F2836EFB600390585 /* UserViewAction.swift */; };
EDA352932836F87600390585 /* CompetitionViewAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDA352922836F87600390585 /* CompetitionViewAction.swift */; };
EDA35298283713C200390585 /* Sharable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDA35297283713C200390585 /* Sharable.swift */; };
EDA61C0B2977243A00370C5C /* HomeContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDA61C0A2977243A00370C5C /* HomeContainerView.swift */; };
EDA61C0D2977276F00370C5C /* RootViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDA61C0C2977276F00370C5C /* RootViewModel.swift */; };
EDA61C0F2977317E00370C5C /* FriendlyCompetitionsAppModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDA61C0E2977317E00370C5C /* FriendlyCompetitionsAppModel.swift */; };
EDAF6C47285277FF002BC0DD /* Nonce.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDAF6C46285277FF002BC0DD /* Nonce.swift */; };
EDB749B72875BC3F00021014 /* StringKeyEncoded.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDB749B62875BC3F00021014 /* StringKeyEncoded.swift */; };
EDBEA170281459D200058A47 /* EditCompetitionSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDBEA16F281459D200058A47 /* EditCompetitionSection.swift */; };
Expand Down Expand Up @@ -333,7 +336,6 @@
ED7881AC2850F6DF00C7F6CB /* SignUpError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpError.swift; sourceTree = "<group>"; };
ED7881AF2850F71E00C7F6CB /* AnalyticsEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsEvent.swift; sourceTree = "<group>"; };
ED8C324629118DC400339988 /* VerifyEmailView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VerifyEmailView.swift; sourceTree = "<group>"; };
ED8C324829118E5500339988 /* FriendlyCompetitionsAppModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FriendlyCompetitionsAppModel.swift; sourceTree = "<group>"; };
ED8D05F6295F5DA1002B3B3A /* CompetitionResultsDateRangeSelector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompetitionResultsDateRangeSelector.swift; sourceTree = "<group>"; };
ED8D05F8295F5DB8002B3B3A /* CompetitionResultsDateRange.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompetitionResultsDateRange.swift; sourceTree = "<group>"; };
ED901B442802426800FE619E /* HomeViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeViewModel.swift; sourceTree = "<group>"; };
Expand All @@ -348,6 +350,7 @@
ED901B702802618700FE619E /* NewCompetitionViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewCompetitionViewModel.swift; sourceTree = "<group>"; };
ED901B732802649200FE619E /* VerifyEmailViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VerifyEmailViewModel.swift; sourceTree = "<group>"; };
ED901B75280265DB00FE619E /* SignInViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInViewModel.swift; sourceTree = "<group>"; };
ED97FCA4297B238B00597A16 /* RootTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootTab.swift; sourceTree = "<group>"; };
EDA035B729173F140091E7A6 /* ArrayBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArrayBuilder.swift; sourceTree = "<group>"; };
EDA035BA2917FE190091E7A6 /* NotificationName+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NotificationName+Extensions.swift"; sourceTree = "<group>"; };
EDA035BD2917FFF90091E7A6 /* Dictionary+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Dictionary+Extensions.swift"; sourceTree = "<group>"; };
Expand All @@ -356,6 +359,9 @@
EDA3528F2836EFB600390585 /* UserViewAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserViewAction.swift; sourceTree = "<group>"; };
EDA352922836F87600390585 /* CompetitionViewAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompetitionViewAction.swift; sourceTree = "<group>"; };
EDA35297283713C200390585 /* Sharable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sharable.swift; sourceTree = "<group>"; };
EDA61C0A2977243A00370C5C /* HomeContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeContainerView.swift; sourceTree = "<group>"; };
EDA61C0C2977276F00370C5C /* RootViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootViewModel.swift; sourceTree = "<group>"; };
EDA61C0E2977317E00370C5C /* FriendlyCompetitionsAppModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FriendlyCompetitionsAppModel.swift; sourceTree = "<group>"; };
EDAF6C46285277FF002BC0DD /* Nonce.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Nonce.swift; sourceTree = "<group>"; };
EDB749B62875BC3F00021014 /* StringKeyEncoded.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringKeyEncoded.swift; sourceTree = "<group>"; };
EDBEA16F281459D200058A47 /* EditCompetitionSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditCompetitionSection.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -651,7 +657,7 @@
C163E30026F2344D00C9EC30 /* Info.plist */,
C1E6406226F4395200E3E70A /* FriendlyCompetitions.entitlements */,
C1691DC626D55FCF006FFA30 /* FriendlyCompetitions.swift */,
ED8C324829118E5500339988 /* FriendlyCompetitionsAppModel.swift */,
EDA61C0E2977317E00370C5C /* FriendlyCompetitionsAppModel.swift */,
C1B2F4E3272B505C0028449F /* AppDelegate.swift */,
C1930E4427C55EF500DB45C1 /* AppState.swift */,
C1A4696926DA823C00254105 /* Factory.swift */,
Expand Down Expand Up @@ -774,7 +780,10 @@
C1ABB20C26D6839900716984 /* Views */ = {
isa = PBXGroup;
children = (
ED97FCA4297B238B00597A16 /* RootTab.swift */,
C19B7F2727BD8A5E00BCA4B9 /* RootView.swift */,
EDA61C0C2977276F00370C5C /* RootViewModel.swift */,
EDA61C0A2977243A00370C5C /* HomeContainerView.swift */,
ED3C09DF29626A1D00ED4ACC /* NavigationDestination.swift */,
C19B7F2E27BEA69200BCA4B9 /* Home */,
C19B7F2927BD8C5C00BCA4B9 /* Explore */,
Expand Down Expand Up @@ -1369,12 +1378,15 @@
ED3868DE29677F8100522722 /* PaywallPurchaseView.swift in Sources */,
C12D640727A5F2FC00259237 /* CompetitionsManager.swift in Sources */,
C1691DC726D55FCF006FFA30 /* FriendlyCompetitions.swift in Sources */,
EDA61C0F2977317E00370C5C /* FriendlyCompetitionsAppModel.swift in Sources */,
C123C9C927A74F3500375F73 /* PermissionsManager.swift in Sources */,
EDA035B829173F140091E7A6 /* ArrayBuilder.swift in Sources */,
7CBF67E827F4BA910047DC81 /* User+Visibility.swift in Sources */,
ED901B4D280247E600FE619E /* CompetitionDetailsViewModel.swift in Sources */,
ED7881AD2850F6DF00C7F6CB /* SignUpError.swift in Sources */,
ED901B6B2802525700FE619E /* FirebaseImageViewModel.swift in Sources */,
EDA61C0D2977276F00370C5C /* RootViewModel.swift in Sources */,
ED97FCA5297B238B00597A16 /* RootTab.swift in Sources */,
ED8C324729118DC400339988 /* VerifyEmailView.swift in Sources */,
C1ABB21526D6987C00716984 /* NewCompetitionView.swift in Sources */,
ED3ED8F7284F951800B5100F /* AutoMockable.generated.swift in Sources */,
Expand Down Expand Up @@ -1451,6 +1463,7 @@
C1C8B24226F3FB47008D6B1B /* HealthKitManager.swift in Sources */,
ED1CFAA22864FF0000192E49 /* WorkoutMetric.swift in Sources */,
C1C1542326D5DFFD00C6FA9F /* HKActivitySummary+Extensions.swift in Sources */,
EDA61C0B2977243A00370C5C /* HomeContainerView.swift in Sources */,
C114314227B9B6ED00915757 /* DeepLink.swift in Sources */,
ED48782E282747BD00AC1E2C /* InviteFriendsView.swift in Sources */,
EDA035BE2917FFF90091E7A6 /* Dictionary+Extensions.swift in Sources */,
Expand All @@ -1477,7 +1490,6 @@
C1C8B24326F3FB47008D6B1B /* ActivitySummaryManager.swift in Sources */,
ED1B5CFE296DBD2400122D7E /* PaywallView.swift in Sources */,
C10E5548272B47080053BBA6 /* XCAssets+Generated.swift in Sources */,
ED8C324929118E5500339988 /* FriendlyCompetitionsAppModel.swift in Sources */,
C1E4AB9826FCC8BD00B1AF12 /* ActivitySummaryInfoView.swift in Sources */,
C16CC40627A7332800C26208 /* UserView.swift in Sources */,
ED438FF927F7C2B900D72F99 /* View+Analytics.swift in Sources */,
Expand Down Expand Up @@ -1692,6 +1704,7 @@
);
MARKETING_VERSION = 1.8.1;
OTHER_LDFLAGS = "-Objc";
OTHER_SWIFT_FLAGS = "-Xfrontend -warn-long-expression-type-checking=200";
PRODUCT_BUNDLE_IDENTIFIER = com.evancooper.FriendlyCompetitions.debug;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "match Development com.evancooper.FriendlyCompetitions.debug";
Expand Down Expand Up @@ -1740,6 +1753,7 @@
);
MARKETING_VERSION = 1.8.1;
OTHER_LDFLAGS = "-Objc";
OTHER_SWIFT_FLAGS = "-Xfrontend -warn-long-expression-type-checking=200";
PRODUCT_BUNDLE_IDENTIFIER = com.evancooper.FriendlyCompetitions;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "match AppStore com.evancooper.FriendlyCompetitions";
Expand Down
24 changes: 19 additions & 5 deletions Friendly Competitions/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import Factory
import Firebase
import FirebaseFirestore
import FirebaseMessaging
import RevenueCat
import UIKit

final class AppDelegate: NSObject, UIApplicationDelegate {
Expand All @@ -13,6 +14,16 @@ final class AppDelegate: NSObject, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
FirebaseApp.configure()
Messaging.messaging().delegate = self

let apiKey: String
#if DEBUG
apiKey = "appl_REFBiyXbqcpKtUtawSUJezooOfQ"
#else
apiKey = "appl_PfCzNKLwrBPhZHDqVcrFOfigEHq"
#endif
Purchases.logLevel = .warn
Purchases.configure(with: .init(withAPIKey: apiKey).with(usesStoreKit2IfAvailable: true))

return true
}

Expand All @@ -26,13 +37,16 @@ extension AppDelegate: MessagingDelegate {
guard let fcmToken = fcmToken, let userId = Auth.auth().currentUser?.uid else { return }

Task {
var user = try await database.document("users/\(userId)")
.getDocument()
let tokens = try await database.document("users/\(userId)")
.getDocument(source: .cache) // can fetch from cache because tokens shouldn't be out of date
.data(as: User.self)
.notificationTokens ?? []

guard user.notificationTokens?.contains(fcmToken) == false else { return }
user.notificationTokens = user.notificationTokens?.appending(fcmToken) ?? [fcmToken]
try await database.document("users/\(userId)").updateDataEncodable(user)
guard !tokens.contains(fcmToken) else { return }
try await database.document("users/\(userId)")
.updateData([
"notificationTokens": tokens.appending(fcmToken)
])
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import ECKit
import Firebase
import FirebaseFirestore
import FirebaseCrashlytics

enum DocumentSnapshotDecodingError: Error {
case missingData
Expand All @@ -15,7 +16,7 @@ public extension DocumentSnapshot {
let data = try JSONSerialization.data(withJSONObject: documentData, options: [])
return try JSONDecoder.shared.decode(T.self, from: data)
} catch {
print(error)
Crashlytics.crashlytics().record(error: error)
throw error
}
}
Expand Down
4 changes: 1 addition & 3 deletions Friendly Competitions/Factory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,12 @@ extension Container {
static let workoutManager = Factory(scope: .shared) { WorkoutManager() as WorkoutManaging }

// Global state
static let appState = Factory(scope: .singleton) { AppState() as AppStateProviding }
static let appState = Factory(scope: .shared) { AppState() as AppStateProviding }

static let database = Factory(scope: .shared) {
let environment = Container.environmentManager.callAsFunction().firestoreEnvironment
let firestore = Firestore.firestore()
let settings = firestore.settings
settings.isPersistenceEnabled = false
settings.cacheSizeBytes = 1_048_576 // 1 MB

switch environment.type {
case .prod:
Expand Down
25 changes: 9 additions & 16 deletions Friendly Competitions/FriendlyCompetitions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,21 @@ struct FriendlyCompetitions: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) private var appDelegate
@StateObject private var appModel = FriendlyCompetitionsAppModel()

@State private var reload = false

var body: some Scene {
WindowGroup {
if reload {
ProgressView().onAppear { reload.toggle() }
} else {
Group {
if appModel.loggedIn {
if appModel.emailVerified {
RootView()
} else {
VerifyEmailView()
}
Group {
if appModel.loggedIn {
if appModel.emailVerified {
RootView()
} else {
SignIn()
VerifyEmailView()
}
} else {
SignIn()
}
.hud(state: $appModel.hud)
.onOpenURL(perform: appModel.handle)
.onReceive(appModel.$environmentUUID.dropFirst()) { _ in reload.toggle() }
}
.hud(state: $appModel.hud)
.onOpenURL(perform: appModel.handle)
}
}
}
8 changes: 0 additions & 8 deletions Friendly Competitions/FriendlyCompetitionsAppModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,18 @@ final class FriendlyCompetitionsAppModel: ObservableObject {
@Published private(set)var loggedIn = false
@Published private(set)var emailVerified = false
@Published var hud: HUD?
@Published private(set) var environmentUUID = UUID()

// MARK: - Private Properties

@Injected(Container.appState) private var appState
@Injected(Container.authenticationManager) private var authenticationManager
@Injected(Container.environmentManager) private var environmentManager

private var cancellables = Set<AnyCancellable>()

// MARK: - Lifecycle

init() {
authenticationManager.loggedIn.assign(to: &$loggedIn)
authenticationManager.emailVerified.assign(to: &$emailVerified)
appState.hud.assign(to: &$hud)

environmentManager.firestoreEnvironmentDidChange
.mapToValue(UUID())
.assign(to: &$environmentUUID)
}

// MARK: - Public Methods
Expand Down
Loading

0 comments on commit 3ee4347

Please sign in to comment.