diff --git a/Twigs.xcodeproj/project.pbxproj b/Twigs.xcodeproj/project.pbxproj index d900e91..042ac01 100644 --- a/Twigs.xcodeproj/project.pbxproj +++ b/Twigs.xcodeproj/project.pbxproj @@ -39,7 +39,6 @@ 28FE6AF823441E1D00D5543E /* Category.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28FE6AF723441E1D00D5543E /* Category.swift */; }; 28FE6AFA23441E3700D5543E /* CategoryDataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28FE6AF923441E3700D5543E /* CategoryDataStore.swift */; }; 28FE6AFC23441E4500D5543E /* CategoryRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28FE6AFB23441E4500D5543E /* CategoryRepository.swift */; }; - 28FE6AFE234428BF00D5543E /* DataStoreProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28FE6AFD234428BF00D5543E /* DataStoreProvider.swift */; }; 28FE6B002344308600D5543E /* Transaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28FE6AFF2344308600D5543E /* Transaction.swift */; }; 28FE6B022344331B00D5543E /* TransactionDataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28FE6B012344331B00D5543E /* TransactionDataStore.swift */; }; 28FE6B04234449DC00D5543E /* TransactionListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28FE6B03234449DC00D5543E /* TransactionListView.swift */; }; @@ -114,7 +113,6 @@ 28FE6AF723441E1D00D5543E /* Category.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Category.swift; sourceTree = ""; }; 28FE6AF923441E3700D5543E /* CategoryDataStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoryDataStore.swift; sourceTree = ""; }; 28FE6AFB23441E4500D5543E /* CategoryRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoryRepository.swift; sourceTree = ""; }; - 28FE6AFD234428BF00D5543E /* DataStoreProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataStoreProvider.swift; sourceTree = ""; }; 28FE6AFF2344308600D5543E /* Transaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Transaction.swift; sourceTree = ""; }; 28FE6B012344331B00D5543E /* TransactionDataStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionDataStore.swift; sourceTree = ""; }; 28FE6B03234449DC00D5543E /* TransactionListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionListView.swift; sourceTree = ""; }; @@ -225,7 +223,6 @@ children = ( 282126A4235BCB7500072D52 /* Twigs.entitlements */, 28AC94FB233C373A00BFB70A /* Info.plist */, - 28FE6AFD234428BF00D5543E /* DataStoreProvider.swift */, 28CE8B9423525F990072BC4C /* Extensions.swift */, 28AC94F1233C373900BFB70A /* LoginView.swift */, 2888234623512DBF003D3847 /* Observable.swift */, @@ -461,7 +458,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 28FE6AFE234428BF00D5543E /* DataStoreProvider.swift in Sources */, 28A1E95A235006A300CA57FE /* AddTransactionView.swift in Sources */, 2821266023555FD300072D52 /* EditTransactionForm.swift in Sources */, 282126622357E45F00072D52 /* TransactionEditView.swift in Sources */, diff --git a/Twigs/Budget/BudgetRepository.swift b/Twigs/Budget/BudgetRepository.swift index bf5b1c7..3f9a6a4 100644 --- a/Twigs/Budget/BudgetRepository.swift +++ b/Twigs/Budget/BudgetRepository.swift @@ -17,51 +17,7 @@ protocol BudgetRepository { func deleteBudget(_ id: String) -> AnyPublisher } -class NetworkBudgetRepository: BudgetRepository { - let apiService: TwigsApiService - let cacheService: TwigsInMemoryCacheService? - - init(_ apiService: TwigsApiService, cacheService: TwigsInMemoryCacheService? = nil) { - self.apiService = apiService - self.cacheService = cacheService - } - - func getBudgets(count: Int?, page: Int?) -> AnyPublisher<[Budget], NetworkError> { - if let budgets = cacheService?.getBudgets(count: count, page: page) { - return budgets - } - - return apiService.getBudgets(count: count, page: page).map { (budgets: [Budget]) in - self.cacheService?.addBudgets(budgets) - return budgets - }.eraseToAnyPublisher() - } - - func getBudget(_ id: String) -> AnyPublisher { - if let budget = cacheService?.getBudget(id) { - return budget - } - return apiService.getBudget(id).map { budget in - self.cacheService?.addBudget(budget) - return budget - }.eraseToAnyPublisher() - } - - func newBudget(_ budget: Budget) -> AnyPublisher { - return apiService.newBudget(budget) - } - - func updateBudget(_ budget: Budget) -> AnyPublisher { - return apiService.updateBudget(budget) - } - - func deleteBudget(_ id: String) -> AnyPublisher { - return apiService.deleteBudget(id) - } -} - #if DEBUG - class MockBudgetRepository: BudgetRepository { static let budget = Budget( id: "1", @@ -95,5 +51,4 @@ class MockBudgetRepository: BudgetRepository { return Result.Publisher(Empty()).eraseToAnyPublisher() } } - #endif diff --git a/Twigs/Budget/BudgetsDataStore.swift b/Twigs/Budget/BudgetsDataStore.swift index 6c74862..4f486cb 100644 --- a/Twigs/Budget/BudgetsDataStore.swift +++ b/Twigs/Budget/BudgetsDataStore.swift @@ -31,6 +31,7 @@ class BudgetsDataStore: ObservableObject { self.budgetRepository = budgetRepository self.categoryRepository = categoryRepository self.transactionRepository = transactionRepository + self.getBudgets(count: nil, page: nil) } func getBudgets(count: Int? = nil, page: Int? = nil) { diff --git a/Twigs/Category/CategoryListView.swift b/Twigs/Category/CategoryListView.swift index 460b670..8a2bb9a 100644 --- a/Twigs/Category/CategoryListView.swift +++ b/Twigs/Category/CategoryListView.swift @@ -51,7 +51,7 @@ struct CategoryListItemView: View { let budget: Budget @State var sumId: String = "" @EnvironmentObject var transactionDataStore: TransactionDataStore - + var progressTintColor: Color { get { if category.expense { diff --git a/Twigs/Category/CategoryRepository.swift b/Twigs/Category/CategoryRepository.swift index d6bf8aa..1d59ce7 100644 --- a/Twigs/Category/CategoryRepository.swift +++ b/Twigs/Category/CategoryRepository.swift @@ -17,64 +17,7 @@ protocol CategoryRepository { func deleteCategory(_ id: String) -> AnyPublisher } -class NetworkCategoryRepository: CategoryRepository { - let apiService: TwigsApiService - let cacheService: TwigsInMemoryCacheService? - - init(_ apiService: TwigsApiService, cacheService: TwigsInMemoryCacheService? = nil) { - self.apiService = apiService - self.cacheService = cacheService - } - - func getCategories(budgetId: String?, expense: Bool?, archived: Bool?, count: Int?, page: Int?) -> AnyPublisher<[Category], NetworkError> { - if let categories = cacheService?.getCategories(budgetId: budgetId, expense: expense, archived: archived, count: count, page: page) { - print("Returning categories from cache") - return categories - } - - print("No cached categories, fetching from network") - return apiService.getCategories(budgetId: budgetId, expense: expense, archived: archived, count: count, page: page).map { (categories: [Category]) in - self.cacheService?.addCategories(categories) - return categories - }.eraseToAnyPublisher() - } - - func getCategory(_ categoryId: String) -> AnyPublisher { - if let category = cacheService?.getCategory(categoryId) { - print("Returning category from cache") - return category - } - print("Category with ID \(categoryId) not cached, returning from network") - return apiService.getCategory(categoryId).map { category in - self.cacheService?.addCategory(category) - return category - }.eraseToAnyPublisher() - } - - func createCategory(_ category: Category) -> AnyPublisher { - return apiService.newCategory(category).map { - self.cacheService?.addCategory($0) - return $0 - }.eraseToAnyPublisher() - } - - func updateCategory(_ category: Category) -> AnyPublisher { - return apiService.updateCategory(category).map { - self.cacheService?.updateCategory($0) - return $0 - }.eraseToAnyPublisher() - } - - func deleteCategory(_ id: String) -> AnyPublisher { - return apiService.deleteCategory(id).map { - self.cacheService?.removeCategory(id) - return $0 - }.eraseToAnyPublisher() - } -} - #if DEBUG - class MockCategoryRepository: CategoryRepository { static let category = Category( budgetId: MockBudgetRepository.budget.id, diff --git a/Twigs/DataStoreProvider.swift b/Twigs/DataStoreProvider.swift deleted file mode 100644 index 45916f9..0000000 --- a/Twigs/DataStoreProvider.swift +++ /dev/null @@ -1,74 +0,0 @@ -// -// DataStoreProvider.swift -// Budget -// -// Created by Billy Brawner on 10/1/19. -// Copyright © 2019 William Brawner. All rights reserved. -// - -import Foundation - -/** - Wrapper for all types of data stores. Some are considered singletons, such as the AuthenticationDataStore, while others are created as needed - */ -class DataStoreProvider { - private let budgetRepository: BudgetRepository - private let categoryRepository: CategoryRepository - private let transactionRepository: TransactionRepository - private let userRepository: UserRepository - - private let _authenticationDataStore: AuthenticationDataStore - - func budgetsDataStore() -> BudgetsDataStore { - return BudgetsDataStore(budgetRepository: budgetRepository, categoryRepository: categoryRepository, transactionRepository: transactionRepository) - } - - func categoryDataStore() -> CategoryDataStore { - return CategoryDataStore(categoryRepository) - } - - func transactionDataStore() -> TransactionDataStore { - return TransactionDataStore(transactionRepository) - } - - func authenticationDataStore() -> AuthenticationDataStore { - return self._authenticationDataStore - } - - func userDataStore() -> UserDataStore { - return UserDataStore(userRepository) - } - - init( - budgetRepository: BudgetRepository, - categoryRepository: CategoryRepository, - transactionRepository: TransactionRepository, - userRepository: UserRepository - ) { - self.budgetRepository = budgetRepository - self.categoryRepository = categoryRepository - self.transactionRepository = transactionRepository - self.userRepository = userRepository - self._authenticationDataStore = AuthenticationDataStore(userRepository) - } -} - -#if DEBUG - -class MockDataStoreProvider: DataStoreProvider { - - override func authenticationDataStore() -> AuthenticationDataStore { - return MockAuthenticationDataStore(MockUserRepository()) - } - - init() { - super.init( - budgetRepository: MockBudgetRepository(), - categoryRepository: MockCategoryRepository(), - transactionRepository: MockTransactionRepository(), - userRepository: MockUserRepository() - ) - } -} - -#endif diff --git a/Twigs/Network/TwigsApiService.swift b/Twigs/Network/TwigsApiService.swift index 88b3941..f12bc28 100644 --- a/Twigs/Network/TwigsApiService.swift +++ b/Twigs/Network/TwigsApiService.swift @@ -9,13 +9,29 @@ import Foundation import Combine -class TwigsApiService: RecurringTransactionsRepository { +class TwigsApiService: BudgetRepository, CategoryRepository, RecurringTransactionsRepository, TransactionRepository, UserRepository { let requestHelper: RequestHelper + convenience init() { + self.init(RequestHelper()) + } + init(_ requestHelper: RequestHelper) { self.requestHelper = requestHelper } + func setToken(_ token: String) { + requestHelper.token = token + } + + func setServer(_ server: String) { + var correctServer = server + if !server.starts(with: "http://") && !server.starts(with: "https://") { + correctServer = "http://\(correctServer)" + } + requestHelper.baseUrl = correctServer + } + // MARK: Budgets func getBudgets(count: Int? = nil, page: Int? = nil) -> AnyPublisher<[Budget], NetworkError> { @@ -47,8 +63,8 @@ class TwigsApiService: RecurringTransactionsRepository { // MARK: Transactions - func getTransactions( - budgetIds: [String]? = nil, + func getTransactions( + budgetIds: [String], categoryIds: [String]? = nil, from: Date? = nil, to: Date? = nil, @@ -56,9 +72,7 @@ class TwigsApiService: RecurringTransactionsRepository { page: Int? = nil ) -> AnyPublisher<[Transaction], NetworkError> { var queries = [String: Array]() - if budgetIds != nil { - queries["budgetIds"] = budgetIds! - } + queries["budgetIds"] = budgetIds if categoryIds != nil { queries["categoryIds"] = categoryIds! } @@ -81,7 +95,7 @@ class TwigsApiService: RecurringTransactionsRepository { return requestHelper.get("/api/transactions/\(id)") } - func newTransaction(_ transaction: Transaction) -> AnyPublisher { + func createTransaction(_ transaction: Transaction) -> AnyPublisher { return requestHelper.post("/api/transactions", data: transaction, type: Transaction.self) } @@ -140,7 +154,7 @@ class TwigsApiService: RecurringTransactionsRepository { return requestHelper.get("/api/categories/\(id)/balance") } - func newCategory(_ category: Category) -> AnyPublisher { + func createCategory(_ category: Category) -> AnyPublisher { return requestHelper.post("/api/categories", data: category, type: Category.self) } @@ -174,11 +188,11 @@ class TwigsApiService: RecurringTransactionsRepository { }.eraseToAnyPublisher() } - func getUser(id: String) -> AnyPublisher { + func getUser(_ id: String) -> AnyPublisher { return requestHelper.get("/api/users/\(id)") } - func searchUsers(query: String) -> AnyPublisher<[User], NetworkError> { + func searchUsers(_ query: String) -> AnyPublisher<[User], NetworkError> { return requestHelper.get( "/api/users/search", queries: ["query": [query]] diff --git a/Twigs/Network/TwigsInMemoryCacheService.swift b/Twigs/Network/TwigsInMemoryCacheService.swift index 95f69eb..4342856 100644 --- a/Twigs/Network/TwigsInMemoryCacheService.swift +++ b/Twigs/Network/TwigsInMemoryCacheService.swift @@ -9,33 +9,35 @@ import Foundation import Combine -class TwigsInMemoryCacheService { +class TwigsInMemoryCacheService: TwigsApiService { var budgets = Set() var categories = Set() var transactions = Set() // MARK: Budgets - func getBudgets(count: Int? = nil, page: Int? = nil) -> AnyPublisher<[Budget], NetworkError>? { + override func getBudgets(count: Int? = nil, page: Int? = nil) -> AnyPublisher<[Budget], NetworkError> { let results = budgets.sorted { (first, second) -> Bool in return first.name < second.name } if results.isEmpty { - return nil + return super.getBudgets(count: count, page: page).map { (budgets: [Budget]) in + self.addBudgets(budgets) + return budgets + }.eraseToAnyPublisher() } return Result.Publisher(.success(results.slice(count: count, page: page))).eraseToAnyPublisher() } - func getBudget(_ id: String) -> AnyPublisher? { + override func getBudget(_ id: String) -> AnyPublisher { guard let budget = budgets.first(where: { $0.id == id }) else { - return nil + return super.getBudget(id).map { budget in + self.addBudget(budget) + return budget + }.eraseToAnyPublisher() } return Result.Publisher(.success(budget)).eraseToAnyPublisher() } - func getBudgetBalance(_ id: String) -> AnyPublisher? { - return nil - } - func addBudgets(_ budgets: [Budget]) { budgets.forEach { addBudget($0) } } @@ -44,24 +46,8 @@ class TwigsInMemoryCacheService { self.budgets.insert(budget) } - // MARK: Transactions - func getTransactions( - budgetIds: [Int]? = nil, - categoryIds: [Int]? = nil, - from: Date? = nil, - to: Date? = nil, - count: Int? = nil, - page: Int? = nil - ) -> AnyPublisher<[Transaction], NetworkError>? { - return nil - } - - func getTransaction(_ id: String) -> AnyPublisher? { - return nil - } - // MARK: Categories - func getCategories(budgetId: String? = nil, expense: Bool? = nil, archived: Bool? = nil, count: Int? = nil, page: Int? = nil) -> AnyPublisher<[Category], NetworkError>? { + override func getCategories(budgetId: String? = nil, expense: Bool? = nil, archived: Bool? = nil, count: Int? = nil, page: Int? = nil) -> AnyPublisher<[Category], NetworkError> { var results = categories if budgetId != nil { results = categories.filter { $0.budgetId == budgetId } @@ -73,23 +59,25 @@ class TwigsInMemoryCacheService { results = results.filter { $0.archived == archived } } if results.isEmpty { - return nil + return super.getCategories(budgetId: budgetId, expense: expense, archived: archived, count: count, page: page).map { (categories: [Category]) in + self.addCategories(categories) + return categories + }.eraseToAnyPublisher() } let sortedResults = results.sorted { $0.title < $1.title } return Result.Publisher(.success(sortedResults.slice(count: count, page: page))).eraseToAnyPublisher() } - func getCategory(_ id: String) -> AnyPublisher? { + override func getCategory(_ id: String) -> AnyPublisher { guard let category = categories.first(where: { $0.id == id }) else { - return nil + return super.getCategory(id).map { category in + self.addCategory(category) + return category + }.eraseToAnyPublisher() } return Result.Publisher(.success(category)).eraseToAnyPublisher() } - func getCategoryBalance(_ id: String) -> AnyPublisher? { - return nil - } - func addCategories(_ categories: [Category]) { categories.forEach { addCategory($0) } } @@ -98,11 +86,26 @@ class TwigsInMemoryCacheService { self.categories.insert(category) } - func updateCategory(_ category: Category) { - if let index = self.categories.firstIndex(where: { $0.id == category.id }) { - self.categories.remove(at: index) - } - self.categories.insert(category) + override func createCategory(_ category: Category) -> AnyPublisher { + return super.createCategory(category).map { + self.categories.insert(category) + return $0 + }.eraseToAnyPublisher() + } + + override func updateCategory(_ category: Category) -> AnyPublisher { + return super.updateCategory(category).map { + self.removeCategory(category.id) + self.categories.insert(category) + return $0 + }.eraseToAnyPublisher() + } + + override func deleteCategory(_ id: String) -> AnyPublisher { + return super.deleteCategory(id).map { + self.removeCategory(id) + return $0 + }.eraseToAnyPublisher() } func removeCategory(_ id: String) { @@ -110,15 +113,6 @@ class TwigsInMemoryCacheService { self.categories.remove(at: index) } } - - // MARK: Users - func getUser(id: String) -> AnyPublisher? { - return nil - } - - func getUsers(count: Int? = nil, page: Int? = nil) -> AnyPublisher<[User], NetworkError>? { - return nil - } } /** diff --git a/Twigs/SidebarBudgetView.swift b/Twigs/SidebarBudgetView.swift index 39360a0..3ea9986 100644 --- a/Twigs/SidebarBudgetView.swift +++ b/Twigs/SidebarBudgetView.swift @@ -10,14 +10,18 @@ import SwiftUI struct SidebarBudgetView: View { @EnvironmentObject var authenticationDataStore: AuthenticationDataStore - @EnvironmentObject var budgetDataStore: BudgetsDataStore - @EnvironmentObject var categoryDataStore: CategoryDataStore + @StateObject var budgetDataStore: BudgetsDataStore let apiService: TwigsApiService @State var isSelectingBudget = true @State var hasSelectedBudget = false @State var isAddingTransaction = false @State var tabSelection: Int? = 0 + init(_ apiService: TwigsApiService) { + self.apiService = apiService + self._budgetDataStore = StateObject(wrappedValue: BudgetsDataStore(budgetRepository: apiService, categoryRepository: apiService, transactionRepository: apiService)) + } + @ViewBuilder var mainView: some View { if case let .success(budget) = budgetDataStore.budget { @@ -26,32 +30,36 @@ struct SidebarBudgetView: View { NavigationLink( tag: 0, selection: $tabSelection, - destination: { BudgetDetailsView(budget: budget).navigationBarTitle("overview") }, - label: { Label("overview", systemImage: "chart.line.uptrend.xyaxis.circle.fill") } + destination: { BudgetDetailsView(budget: budget).navigationBarTitle("overview") + }, + label: { Label("overview", systemImage: "chart.line.uptrend.xyaxis") } ) - .keyboardShortcut("1") + .keyboardShortcut("1") NavigationLink( tag: 1, selection: $tabSelection, destination: { TransactionListView(budget).navigationBarTitle("transactions") }, - label: { Label("transactions", systemImage: "dollarsign.circle.fill") }) - .keyboardShortcut("2") + label: { Label("transactions", systemImage: "dollarsign.circle") }) + .keyboardShortcut("2") NavigationLink( tag: 2, selection: $tabSelection, destination: { CategoryListView(budget).navigationBarTitle("categories") }, - label: { Label("categories", systemImage: "chart.pie.fill") }) - .keyboardShortcut("3") + label: { Label("categories", systemImage: "chart.pie") }) + .keyboardShortcut("3") NavigationLink( tag: 3, selection: $tabSelection, destination: { RecurringTransactionsListView(dataStore: RecurringTransactionDataStore(apiService, budgetId: budget.id)).navigationBarTitle("recurring_transactions") }, - label: { Label("recurring_transactions", systemImage: "arrow.triangle.2.circlepath.circle.fill") }) - .keyboardShortcut("4") + label: { Label("recurring_transactions", systemImage: "arrow.triangle.2.circlepath") }) + .keyboardShortcut("4") BudgetListsView() } .navigationTitle(budget.name) - } + }.environmentObject(TransactionDataStore(apiService)) + .environmentObject(CategoryDataStore(apiService)) + .environmentObject(budgetDataStore) + .environmentObject(UserDataStore(apiService)) } else { ActivityIndicator(isAnimating: .constant(true), style: .large) } @@ -60,17 +68,17 @@ struct SidebarBudgetView: View { @ViewBuilder var body: some View { mainView - .sheet(isPresented: $authenticationDataStore.showLogin, - onDismiss: { - self.budgetDataStore.getBudgets() - }, - content: { - LoginView() - .environmentObject(authenticationDataStore) - .onDisappear { - self.budgetDataStore.getBudgets() - } - }) + .sheet(isPresented: $authenticationDataStore.showLogin, + onDismiss: { + self.budgetDataStore.getBudgets() + }, + content: { + LoginView() + .environmentObject(authenticationDataStore) + .onDisappear { + self.budgetDataStore.getBudgets() + } + }) .interactiveDismissDisabled(true) } } diff --git a/Twigs/TabbedBudgetView.swift b/Twigs/TabbedBudgetView.swift index 9ba97bf..862c9d7 100644 --- a/Twigs/TabbedBudgetView.swift +++ b/Twigs/TabbedBudgetView.swift @@ -10,14 +10,18 @@ import SwiftUI struct TabbedBudgetView: View { @EnvironmentObject var authenticationDataStore: AuthenticationDataStore - @EnvironmentObject var budgetDataStore: BudgetsDataStore - @EnvironmentObject var categoryDataStore: CategoryDataStore + @StateObject var budgetDataStore: BudgetsDataStore let apiService: TwigsApiService @State var isSelectingBudget = true @State var hasSelectedBudget = false @State var isAddingTransaction = false @State var tabSelection: Int = 0 + init(_ apiService: TwigsApiService) { + self.apiService = apiService + self._budgetDataStore = StateObject(wrappedValue: BudgetsDataStore(budgetRepository: apiService, categoryRepository: apiService, transactionRepository: apiService)) + } + @ViewBuilder var mainView: some View { if case let .success(budget) = budgetDataStore.budget { @@ -75,7 +79,10 @@ struct TabbedBudgetView: View { } .tag(3) .keyboardShortcut("4") - } + }.environmentObject(TransactionDataStore(apiService)) + .environmentObject(CategoryDataStore(apiService)) + .environmentObject(budgetDataStore) + .environmentObject(UserDataStore(apiService)) } else { ActivityIndicator(isAnimating: .constant(true), style: .large) } diff --git a/Twigs/Transaction/TransactionDataStore.swift b/Twigs/Transaction/TransactionDataStore.swift index 0a5850e..ae78861 100644 --- a/Twigs/Transaction/TransactionDataStore.swift +++ b/Twigs/Transaction/TransactionDataStore.swift @@ -14,9 +14,7 @@ class TransactionDataStore: ObservableObject { private var currentRequest: AnyCancellable? = nil private var sumRequests: [String:AnyCancellable] = [:] @Published var transactions: [String:Result, NetworkError>] = ["": .failure(.loading)] - @Published var transaction: Result = .failure(.unknown) - @Published var sums: [String:Result] = ["": .failure(.loading)] func getTransactions(_ budgetId: String, categoryId: String? = nil, from: Date? = nil, count: Int? = nil, page: Int? = nil) -> String { @@ -31,6 +29,7 @@ class TransactionDataStore: ObservableObject { budgetIds: [budgetId], categoryIds: categoryIds, from: from ?? Date.firstOfMonth, + to: nil, count: count, page: page ) diff --git a/Twigs/Transaction/TransactionRepository.swift b/Twigs/Transaction/TransactionRepository.swift index e8727c2..411f604 100644 --- a/Twigs/Transaction/TransactionRepository.swift +++ b/Twigs/Transaction/TransactionRepository.swift @@ -10,7 +10,7 @@ import Foundation import Combine protocol TransactionRepository { - func getTransactions(budgetIds: [String], categoryIds: [String]?, from: Date?, count: Int?, page: Int?) -> AnyPublisher<[Transaction], NetworkError> + func getTransactions(budgetIds: [String], categoryIds: [String]?, from: Date?, to: Date?, count: Int?, page: Int?) -> AnyPublisher<[Transaction], NetworkError> func getTransaction(_ transactionId: String) -> AnyPublisher func createTransaction(_ transaction: Transaction) -> AnyPublisher func updateTransaction(_ transaction: Transaction) -> AnyPublisher @@ -18,38 +18,6 @@ protocol TransactionRepository { func sumTransactions(budgetId: String?, categoryId: String?, from: Date?, to: Date?) -> AnyPublisher } -class NetworkTransactionRepository: TransactionRepository { - let apiService: TwigsApiService - - init(_ apiService: TwigsApiService) { - self.apiService = apiService - } - - func getTransactions(budgetIds: [String], categoryIds: [String]?, from: Date?, count: Int?, page: Int?) -> AnyPublisher<[Transaction], NetworkError> { - return apiService.getTransactions(budgetIds: budgetIds, categoryIds: categoryIds, from: from, count: count, page: page) - } - - func getTransaction(_ transactionId: String) -> AnyPublisher { - return apiService.getTransaction(transactionId) - } - - func createTransaction(_ transaction: Transaction) -> AnyPublisher { - return apiService.newTransaction(transaction) - } - - func updateTransaction(_ transaction: Transaction) -> AnyPublisher { - return apiService.updateTransaction(transaction) - } - - func deleteTransaction(_ transactionId: String) -> AnyPublisher { - return apiService.deleteTransaction(transactionId) - } - - func sumTransactions(budgetId: String?, categoryId: String?, from: Date?, to: Date?) -> AnyPublisher { - return apiService.sumTransactions(budgetId: budgetId, categoryId: categoryId, from: from, to: to) - } -} - #if DEBUG class MockTransactionRepository: TransactionRepository { static let transaction: Transaction = Transaction( @@ -64,7 +32,7 @@ class MockTransactionRepository: TransactionRepository { budgetId: MockBudgetRepository.budget.id ) - func getTransactions(budgetIds: [String], categoryIds: [String]?, from: Date?, count: Int?, page: Int?) -> AnyPublisher<[Transaction], NetworkError> { + func getTransactions(budgetIds: [String], categoryIds: [String]?, from: Date?, to: Date?, count: Int?, page: Int?) -> AnyPublisher<[Transaction], NetworkError> { return Result.Publisher([MockTransactionRepository.transaction]).eraseToAnyPublisher() } diff --git a/Twigs/TwigsApp.swift b/Twigs/TwigsApp.swift index 3d5993a..c4fa393 100644 --- a/Twigs/TwigsApp.swift +++ b/Twigs/TwigsApp.swift @@ -10,46 +10,28 @@ import SwiftUI @main struct TwigsApp: App { - let requestHelper = RequestHelper() - let cacheService = TwigsInMemoryCacheService() - let apiService: TwigsApiService - let budgetRepository: BudgetRepository - let categoryRepository: CategoryRepository - let transactionRepository:TransactionRepository - let userRepository: UserRepository - let dataStoreProvider: DataStoreProvider + @StateObject var authDataStore: AuthenticationDataStore + let apiService: TwigsApiService = TwigsInMemoryCacheService() init() { - self.apiService = TwigsApiService(requestHelper) - self.budgetRepository = NetworkBudgetRepository(apiService, cacheService: cacheService) - self.categoryRepository = NetworkCategoryRepository(apiService, cacheService: cacheService) - self.transactionRepository = NetworkTransactionRepository(apiService) - self.userRepository = NetworkUserRepository(apiService) - self.dataStoreProvider = DataStoreProvider( - budgetRepository: budgetRepository, - categoryRepository: categoryRepository, - transactionRepository: transactionRepository, - userRepository: userRepository - ) + let authDataStore = AuthenticationDataStore(self.apiService) + self._authDataStore = StateObject(wrappedValue: authDataStore) } - + @ViewBuilder var mainView: some View { if UIDevice.current.userInterfaceIdiom == .mac || UIDevice.current.userInterfaceIdiom == .pad { - SidebarBudgetView(apiService: apiService) + SidebarBudgetView(apiService) + .environmentObject(authDataStore) } else { - TabbedBudgetView(apiService: apiService) + TabbedBudgetView(apiService) + .environmentObject(authDataStore) } } var body: some Scene { WindowGroup { mainView - .environmentObject(dataStoreProvider.authenticationDataStore()) - .environmentObject(dataStoreProvider.budgetsDataStore()) - .environmentObject(dataStoreProvider.categoryDataStore()) - .environmentObject(dataStoreProvider.transactionDataStore()) - .environmentObject(dataStoreProvider.userDataStore()) } } } diff --git a/Twigs/User/UserRepository.swift b/Twigs/User/UserRepository.swift index 161cd2d..543fc50 100644 --- a/Twigs/User/UserRepository.swift +++ b/Twigs/User/UserRepository.swift @@ -18,42 +18,6 @@ protocol UserRepository { func register(username: String, email: String, password: String) -> AnyPublisher } -class NetworkUserRepository: UserRepository { - let apiService: TwigsApiService - - init(_ apiService: TwigsApiService) { - self.apiService = apiService - } - - func setToken(_ token: String) { - self.apiService.requestHelper.token = token - } - - func getUser(_ id: String) -> AnyPublisher { - return apiService.getUser(id: id) - } - - func searchUsers(_ withUsername: String) -> AnyPublisher<[User], NetworkError> { - return apiService.searchUsers(query: withUsername) - } - - func setServer(_ server: String) { - var correctServer = server - if !server.starts(with: "http://") && !server.starts(with: "https://") { - correctServer = "http://\(correctServer)" - } - apiService.requestHelper.baseUrl = correctServer - } - - func login(username: String, password: String) -> AnyPublisher { - return apiService.login(username: username, password: password) - } - - func register(username: String, email: String, password: String) -> AnyPublisher { - return apiService.register(username: username, email: email, password: password) - } -} - #if DEBUG class MockUserRepository: UserRepository {