diff --git a/Twigs.xcodeproj/project.pbxproj b/Twigs.xcodeproj/project.pbxproj index 4694e9a..5aff051 100644 --- a/Twigs.xcodeproj/project.pbxproj +++ b/Twigs.xcodeproj/project.pbxproj @@ -39,6 +39,10 @@ 801D08CE275F189E00931465 /* RecurringTransactionsRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 801D08CD275F189E00931465 /* RecurringTransactionsRepository.swift */; }; 801D08D2275FB7DE00931465 /* RecurringTransactionDetailsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 801D08D1275FB7DE00931465 /* RecurringTransactionDetailsView.swift */; }; 802161D0277647920075761A /* AsyncObservableObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 802161CF277647920075761A /* AsyncObservableObject.swift */; }; + 8043704028CBEC6800F229F9 /* FirebaseAnalyticsWithoutAdIdSupport in Frameworks */ = {isa = PBXBuildFile; productRef = 8043703F28CBEC6800F229F9 /* FirebaseAnalyticsWithoutAdIdSupport */; }; + 8043704228CBEC6800F229F9 /* FirebaseCrashlytics in Frameworks */ = {isa = PBXBuildFile; productRef = 8043704128CBEC6800F229F9 /* FirebaseCrashlytics */; }; + 8043704528CBEDF400F229F9 /* ErrorReporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8043704428CBEDF400F229F9 /* ErrorReporter.swift */; }; + 8043704728CBF16600F229F9 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 8043704628CBF16600F229F9 /* GoogleService-Info.plist */; }; 8043EB84271F26ED00498E73 /* CategoryDetailsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8043EB83271F26ED00498E73 /* CategoryDetailsView.swift */; }; 8044BA3927828E9D009A78D4 /* CategoryDataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8044BA3827828E9D009A78D4 /* CategoryDataStore.swift */; }; 8044BA3B2784B659009A78D4 /* TransactionDetails.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8044BA3A2784B659009A78D4 /* TransactionDetails.swift */; }; @@ -136,6 +140,8 @@ 801D08D1275FB7DE00931465 /* RecurringTransactionDetailsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecurringTransactionDetailsView.swift; sourceTree = ""; }; 802161CF277647920075761A /* AsyncObservableObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncObservableObject.swift; sourceTree = ""; }; 8021EFAB280A0FA100043F18 /* TwigsCore */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = TwigsCore; path = ../TwigsCore; sourceTree = ""; }; + 8043704428CBEDF400F229F9 /* ErrorReporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorReporter.swift; sourceTree = ""; }; + 8043704628CBF16600F229F9 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "../../../Downloads/GoogleService-Info.plist"; sourceTree = ""; }; 8043EB83271F26ED00498E73 /* CategoryDetailsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoryDetailsView.swift; sourceTree = ""; }; 8044BA3827828E9D009A78D4 /* CategoryDataStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoryDataStore.swift; sourceTree = ""; }; 8044BA3A2784B659009A78D4 /* TransactionDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionDetails.swift; sourceTree = ""; }; @@ -168,7 +174,9 @@ files = ( 80D06DD1288C817800B50467 /* TwigsCore in Frameworks */, 8076A8522809FE99006B9DC9 /* Collections in Frameworks */, + 8043704228CBEC6800F229F9 /* FirebaseCrashlytics in Frameworks */, 8076A84F2809FE8E006B9DC9 /* ArgumentParser in Frameworks */, + 8043704028CBEC6800F229F9 /* FirebaseAnalyticsWithoutAdIdSupport in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -251,13 +259,13 @@ 28AC94E1233C373900BFB70A = { isa = PBXGroup; children = ( + 8005FD59277E623900E48B23 /* Frameworks */, 80DBED432774AE4F00CB0A88 /* Packages */, - 80A419EB2787C0A00090C515 /* twigs-cli */, 28AC94EB233C373900BFB70A /* Products */, 28AC94EC233C373900BFB70A /* Twigs */, + 80A419EB2787C0A00090C515 /* twigs-cli */, 28AC9503233C373A00BFB70A /* TwigsTests */, 28AC950E233C373A00BFB70A /* TwigsUITests */, - 8005FD59277E623900E48B23 /* Frameworks */, ); sourceTree = ""; }; @@ -275,6 +283,7 @@ 28AC94EC233C373900BFB70A /* Twigs */ = { isa = PBXGroup; children = ( + 8043704628CBF16600F229F9 /* GoogleService-Info.plist */, 282126A4235BCB7500072D52 /* Twigs.entitlements */, 28AC94FB233C373A00BFB70A /* Info.plist */, 28CE8B9423525F990072BC4C /* Extensions.swift */, @@ -298,6 +307,7 @@ 802161CF277647920075761A /* AsyncObservableObject.swift */, 800DFC2B277FF47A00EDCE9B /* AsyncData.swift */, 80D2CE192833448500EDD6C2 /* DataStore.swift */, + 8043704428CBEDF400F229F9 /* ErrorReporter.swift */, ); path = Twigs; sourceTree = ""; @@ -404,6 +414,7 @@ 28AC94E6233C373900BFB70A /* Sources */, 28AC94E7233C373900BFB70A /* Frameworks */, 28AC94E8233C373900BFB70A /* Resources */, + 8043704328CBED4000F229F9 /* ShellScript */, ); buildRules = ( ); @@ -414,6 +425,8 @@ 8076A84E2809FE8E006B9DC9 /* ArgumentParser */, 8076A8512809FE99006B9DC9 /* Collections */, 80D06DD0288C817800B50467 /* TwigsCore */, + 8043703F28CBEC6800F229F9 /* FirebaseAnalyticsWithoutAdIdSupport */, + 8043704128CBEC6800F229F9 /* FirebaseCrashlytics */, ); productName = Budget; productReference = 28AC94EA233C373900BFB70A /* Twigs.app */; @@ -517,6 +530,7 @@ 8076A84A2809FE56006B9DC9 /* XCRemoteSwiftPackageReference "swift-argument-parser" */, 8076A84D2809FE8D006B9DC9 /* XCRemoteSwiftPackageReference "swift-argument-parser" */, 8076A8502809FE99006B9DC9 /* XCRemoteSwiftPackageReference "swift-collections" */, + 8043703E28CBEC6800F229F9 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */, ); productRefGroup = 28AC94EB233C373900BFB70A /* Products */; projectDirPath = ""; @@ -537,6 +551,7 @@ files = ( 28AC94FA233C373A00BFB70A /* LaunchScreen.storyboard in Resources */, 28AC951F233C381C00BFB70A /* Localizable.strings in Resources */, + 8043704728CBF16600F229F9 /* GoogleService-Info.plist in Resources */, 28AC94F7233C373A00BFB70A /* Preview Assets.xcassets in Resources */, 28AC94F4233C373A00BFB70A /* Assets.xcassets in Resources */, ); @@ -558,6 +573,28 @@ }; /* End PBXResourcesBuildPhase section */ +/* Begin PBXShellScriptBuildPhase section */ + 8043704328CBED4000F229F9 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Resources/DWARF/${TARGET_NAME}", + "$(SRCROOT)/newInputFile", + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "# Type a script or drag a script file from your workspace to insert its path.\n\"${BUILD_DIR%/Build/*}/SourcePackages/checkouts/firebase-ios-sdk/Crashlytics/run\"\n"; + }; +/* End PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ 28AC94E6233C373900BFB70A /* Sources */ = { isa = PBXSourcesBuildPhase; @@ -604,6 +641,7 @@ 284102302342D97300EAFA29 /* BudgetListsView.swift in Sources */, 282126BD235CDE1400072D52 /* ProgressView.swift in Sources */, 806C7850272B700B00FA1375 /* TwigsApp.swift in Sources */, + 8043704528CBEDF400F229F9 /* ErrorReporter.swift in Sources */, 808CA1A928355B30002EDD59 /* BudgetFormView.swift in Sources */, 80AF7A982835ED3B009565C6 /* RecurringTransactionFormView.swift in Sources */, 28CE8B9523525F990072BC4C /* Extensions.swift in Sources */, @@ -800,7 +838,8 @@ CODE_SIGN_ENTITLEMENTS = Twigs/Twigs.entitlements; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 18; + CURRENT_PROJECT_VERSION = 19; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DERIVE_MACCATALYST_PRODUCT_BUNDLE_IDENTIFIER = YES; DEVELOPMENT_ASSET_PATHS = "\"Twigs/Preview Content\""; DEVELOPMENT_TEAM = 9Z6DE6KNJ9; @@ -829,7 +868,7 @@ CODE_SIGN_ENTITLEMENTS = Twigs/Twigs.entitlements; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 18; + CURRENT_PROJECT_VERSION = 19; DERIVE_MACCATALYST_PRODUCT_BUNDLE_IDENTIFIER = YES; DEVELOPMENT_ASSET_PATHS = "\"Twigs/Preview Content\""; DEVELOPMENT_TEAM = 9Z6DE6KNJ9; @@ -1014,6 +1053,14 @@ /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ + 8043703E28CBEC6800F229F9 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/firebase/firebase-ios-sdk"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 9.0.0; + }; + }; 8076A84A2809FE56006B9DC9 /* XCRemoteSwiftPackageReference "swift-argument-parser" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/apple/swift-argument-parser.git"; @@ -1057,6 +1104,16 @@ /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ + 8043703F28CBEC6800F229F9 /* FirebaseAnalyticsWithoutAdIdSupport */ = { + isa = XCSwiftPackageProductDependency; + package = 8043703E28CBEC6800F229F9 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseAnalyticsWithoutAdIdSupport; + }; + 8043704128CBEC6800F229F9 /* FirebaseCrashlytics */ = { + isa = XCSwiftPackageProductDependency; + package = 8043703E28CBEC6800F229F9 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseCrashlytics; + }; 8076A84E2809FE8E006B9DC9 /* ArgumentParser */ = { isa = XCSwiftPackageProductDependency; package = 80A419F12787C13E0090C515 /* XCRemoteSwiftPackageReference "swift-argument-parser" */; diff --git a/Twigs.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Twigs.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index fa4219d..ccbcf1d 100644 --- a/Twigs.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Twigs.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,6 +1,105 @@ { "object": { "pins": [ + { + "package": "abseil", + "repositoryURL": "https://github.com/firebase/abseil-cpp-SwiftPM.git", + "state": { + "branch": null, + "revision": "583de9bd60f66b40e78d08599cc92036c2e7e4e1", + "version": "0.20220203.2" + } + }, + { + "package": "BoringSSL-GRPC", + "repositoryURL": "https://github.com/firebase/boringssl-SwiftPM.git", + "state": { + "branch": null, + "revision": "dd3eda2b05a3f459fc3073695ad1b28659066eab", + "version": "0.9.1" + } + }, + { + "package": "Firebase", + "repositoryURL": "https://github.com/firebase/firebase-ios-sdk", + "state": { + "branch": null, + "revision": "7f31a43f8c49bd4a1723bc9fecdfaa4411dd9f36", + "version": "9.5.0" + } + }, + { + "package": "GoogleAppMeasurement", + "repositoryURL": "https://github.com/google/GoogleAppMeasurement.git", + "state": { + "branch": null, + "revision": "f54f60d0164d887e1174fa51ab2efe48a8e9d178", + "version": "9.3.0" + } + }, + { + "package": "GoogleDataTransport", + "repositoryURL": "https://github.com/google/GoogleDataTransport.git", + "state": { + "branch": null, + "revision": "5056b15c5acbb90cd214fe4d6138bdf5a740e5a8", + "version": "9.2.0" + } + }, + { + "package": "GoogleUtilities", + "repositoryURL": "https://github.com/google/GoogleUtilities.git", + "state": { + "branch": null, + "revision": "f4abe56ce62a779e64b525eb133c8fc2a84bbc1f", + "version": "7.7.1" + } + }, + { + "package": "gRPC", + "repositoryURL": "https://github.com/grpc/grpc-ios.git", + "state": { + "branch": null, + "revision": "8440b914756e0d26d4f4d054a1c1581daedfc5b6", + "version": "1.44.3-grpc" + } + }, + { + "package": "GTMSessionFetcher", + "repositoryURL": "https://github.com/google/gtm-session-fetcher.git", + "state": { + "branch": null, + "revision": "19605024d59eaefdb1f6a2cb11ebe75df4421126", + "version": "2.0.0" + } + }, + { + "package": "leveldb", + "repositoryURL": "https://github.com/firebase/leveldb.git", + "state": { + "branch": null, + "revision": "0706abcc6b0bd9cedfbb015ba840e4a780b5159b", + "version": "1.22.2" + } + }, + { + "package": "nanopb", + "repositoryURL": "https://github.com/firebase/nanopb.git", + "state": { + "branch": null, + "revision": "819d0a2173aff699fb8c364b6fb906f7cdb1a692", + "version": "2.30909.0" + } + }, + { + "package": "Promises", + "repositoryURL": "https://github.com/google/promises.git", + "state": { + "branch": null, + "revision": "3e4e743631e86c8c70dbc6efdc7beaa6e90fd3bb", + "version": "2.1.1" + } + }, { "package": "swift-argument-parser", "repositoryURL": "https://github.com/apple/swift-argument-parser.git", @@ -18,6 +117,15 @@ "revision": "48254824bb4248676bf7ce56014ff57b142b77eb", "version": "1.0.2" } + }, + { + "package": "SwiftProtobuf", + "repositoryURL": "https://github.com/apple/swift-protobuf.git", + "state": { + "branch": null, + "revision": "b8230909dedc640294d7324d37f4c91ad3dcf177", + "version": "1.20.1" + } } ] }, diff --git a/Twigs/DataStore.swift b/Twigs/DataStore.swift index 29c28b9..92d38af 100644 --- a/Twigs/DataStore.swift +++ b/Twigs/DataStore.swift @@ -16,6 +16,7 @@ private let LAST_BUDGET = "LAST_BUDGET" @MainActor class DataStore : ObservableObject { let apiService: TwigsApiService + let errorReporter: ErrorReporter @Published var budgets: AsyncData<[Budget]> = .empty @Published var budget: AsyncData = .empty { didSet { @@ -66,9 +67,11 @@ class DataStore : ObservableObject { } init( - _ apiService: TwigsApiService + _ apiService: TwigsApiService, + errorReporter: ErrorReporter = LoggingErrorReporter() ) { self.apiService = apiService + self.errorReporter = errorReporter self.baseUrl = UserDefaults.standard.string(forKey: KEY_BASE_URL) ?? "" self.apiService.baseUrl = baseUrl self.token = UserDefaults.standard.string(forKey: KEY_TOKEN) @@ -95,6 +98,7 @@ class DataStore : ObservableObject { } } } catch { + self.errorReporter.reportError(error: error) self.budgets = .error(error) showBudgetSelection = true } @@ -120,6 +124,7 @@ class DataStore : ObservableObject { self.budgets = .success(updatedBudgets.sorted(by: { $0.name < $1.name })) } } catch { + self.errorReporter.reportError(error: error) self.budget = .error(error, budget) } } @@ -136,6 +141,7 @@ class DataStore : ObservableObject { self.budgets = .success(budgets.filter(withoutId: budget.id)) } } catch { + self.errorReporter.reportError(error: error) self.budget = .error(error, budget) } } @@ -188,6 +194,7 @@ class DataStore : ObservableObject { } self.overview = .success(budgetOverview) } catch { + self.errorReporter.reportError(error: error) self.overview = .error(error) } } @@ -241,6 +248,7 @@ class DataStore : ObservableObject { let categories = try await apiService.getCategories(budgetId: budgetId, expense: expense, archived: archived, count: count, page: page) self.categories = .success(categories) } catch { + self.errorReporter.reportError(error: error) self.categories = .error(error) } } @@ -262,6 +270,7 @@ class DataStore : ObservableObject { self.categories = .success(updatedCategories.sorted(by: { $0.title < $1.title })) } } catch { + self.errorReporter.reportError(error: error) self.category = .error(error, category) } } @@ -276,6 +285,7 @@ class DataStore : ObservableObject { self.categories = .success(categories.filter(withoutId: category.id)) } } catch { + self.errorReporter.reportError(error: error) self.category = .error(error, category) } } @@ -336,6 +346,7 @@ class DataStore : ObservableObject { } self.recurringTransactions = .success(recurringTransactions) } catch { + self.errorReporter.reportError(error: error) self.recurringTransactions = .error(error) } } @@ -381,6 +392,7 @@ class DataStore : ObservableObject { } await self.getRecurringTransactions() } catch { + self.errorReporter.reportError(error: error) self.recurringTransactions = .error(error) } } @@ -392,6 +404,7 @@ class DataStore : ObservableObject { self.recurringTransaction = .empty await self.getRecurringTransactions() } catch { + self.errorReporter.reportError(error: error) self.recurringTransaction = .error(error, transaction) } } @@ -436,6 +449,7 @@ class DataStore : ObservableObject { let groupedTransactions = OrderedDictionary(grouping: transactions, by: { $0.date.toLocaleString() }) self.transactions = .success(groupedTransactions) } catch { + self.errorReporter.reportError(error: error) self.transactions = .error(error) } } @@ -456,6 +470,7 @@ class DataStore : ObservableObject { } await getTransactions() } catch { + self.errorReporter.reportError(error: error) self.transaction = .error(error, transaction) } } @@ -467,6 +482,7 @@ class DataStore : ObservableObject { self.transaction = .empty await getTransactions() } catch { + self.errorReporter.reportError(error: error) self.transaction = .error(error, transaction) } } @@ -555,6 +571,7 @@ class DataStore : ObservableObject { self.userId = response.userId await self.loadProfile() } catch { + self.errorReporter.reportError(error: error) switch error { case NetworkError.jsonParsingFailed(let jsonError): print(jsonError.localizedDescription) @@ -589,6 +606,7 @@ class DataStore : ObservableObject { do { _ = try await apiService.register(username: username, email: email, password: password) } catch { + self.errorReporter.reportError(error: error) switch error { case NetworkError.jsonParsingFailed(let jsonError): print(jsonError.localizedDescription) @@ -630,6 +648,7 @@ class DataStore : ObservableObject { self.currentUser = .success(user) await getBudgets() } catch { + self.errorReporter.reportError(error: error) self.currentUser = .error(error) } } @@ -644,6 +663,7 @@ class DataStore : ObservableObject { self.currentUser = .success(updated) return nil } catch { + self.errorReporter.reportError(error: error) self.currentUser = .error(error, current) return .unavailable } @@ -662,6 +682,7 @@ class DataStore : ObservableObject { self.currentUser = .success(updated) return nil } catch { + self.errorReporter.reportError(error: error) self.currentUser = .error(error, current) return .unavailable } @@ -680,6 +701,7 @@ class DataStore : ObservableObject { self.currentUser = .success(updated) return nil } catch { + self.errorReporter.reportError(error: error) self.currentUser = .error(error, current) return .unknown } @@ -695,6 +717,7 @@ class DataStore : ObservableObject { self.currentUser = .success(updated) return true } catch { + self.errorReporter.reportError(error: error) self.currentUser = .error(error, current) return false } @@ -707,6 +730,7 @@ class DataStore : ObservableObject { let user = try await self.apiService.getUser(id) self.user = .success(user) } catch { + self.errorReporter.reportError(error: error) self.currentUser = .error(error) } } diff --git a/Twigs/ErrorReporter.swift b/Twigs/ErrorReporter.swift new file mode 100644 index 0000000..5ca8262 --- /dev/null +++ b/Twigs/ErrorReporter.swift @@ -0,0 +1,26 @@ +// +// ErrorReporter.swift +// Twigs +// +// Created by William Brawner on 9/9/22. +// Copyright © 2022 William Brawner. All rights reserved. +// + +import Foundation +import FirebaseCrashlytics + +protocol ErrorReporter { + func reportError(error: Error) +} + +class LoggingErrorReporter: ErrorReporter { + func reportError(error: Error) { + print(error) + } +} + +class FirebaseErrorReporter: ErrorReporter { + func reportError(error: Error) { + Crashlytics.crashlytics().record(error: error) + } +} diff --git a/Twigs/GoogleService-Info.plist b/Twigs/GoogleService-Info.plist new file mode 100644 index 0000000..a6e82bf --- /dev/null +++ b/Twigs/GoogleService-Info.plist @@ -0,0 +1,36 @@ + + + + + CLIENT_ID + 527070722499-8qtkq1oqkveapng949atmdt7l38r75ps.apps.googleusercontent.com + REVERSED_CLIENT_ID + com.googleusercontent.apps.527070722499-8qtkq1oqkveapng949atmdt7l38r75ps + API_KEY + AIzaSyDzEcz1sz65JXpujOfFrRqUG2kD_tooA50 + GCM_SENDER_ID + 527070722499 + PLIST_VERSION + 1 + BUNDLE_ID + com.wbrawner.projects.budget.ios + PROJECT_ID + budget-c7da5 + STORAGE_BUCKET + budget-c7da5.appspot.com + IS_ADS_ENABLED + + IS_ANALYTICS_ENABLED + + IS_APPINVITE_ENABLED + + IS_GCM_ENABLED + + IS_SIGNIN_ENABLED + + GOOGLE_APP_ID + 1:527070722499:ios:0e0c4e20d30697df73e576 + DATABASE_URL + https://budget-c7da5.firebaseio.com + + \ No newline at end of file diff --git a/Twigs/Views/MainView.swift b/Twigs/Views/MainView.swift index a24e26a..79a3641 100644 --- a/Twigs/Views/MainView.swift +++ b/Twigs/Views/MainView.swift @@ -6,16 +6,26 @@ // Copyright © 2021 William Brawner. All rights reserved. // +import FirebaseCore import SwiftUI import TwigsCore +class AppDelegate: NSObject, UIApplicationDelegate { + func application(_ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { + FirebaseApp.configure() + return true + } +} + struct MainView: View { + @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate @StateObject var dataStore: DataStore let apiService: TwigsApiService init(_ apiService: TwigsApiService) { self.apiService = apiService - self._dataStore = StateObject(wrappedValue: DataStore(apiService)) + self._dataStore = StateObject(wrappedValue: DataStore(apiService, errorReporter: FirebaseErrorReporter())) } @ViewBuilder