From c4555fe80457f5d51dc201eb2a87c420971daefb Mon Sep 17 00:00:00 2001 From: William Brawner Date: Sat, 23 Jul 2022 15:57:31 -0600 Subject: [PATCH] Fix category list showing all transactions --- .gitignore | 1 + Twigs.xcodeproj/project.pbxproj | 18 ++--- Twigs/Category/CategoryDetailsView.swift | 4 +- Twigs/DataStore.swift | 80 ++++++++++----------- Twigs/Transaction/TransactionListView.swift | 43 +++++------ 5 files changed, 74 insertions(+), 72 deletions(-) diff --git a/.gitignore b/.gitignore index 330d167..4f20167 100644 --- a/.gitignore +++ b/.gitignore @@ -88,3 +88,4 @@ fastlane/test_output # https://github.com/johnno1962/injectionforxcode iOSInjectionProject/ +.DS_Store diff --git a/Twigs.xcodeproj/project.pbxproj b/Twigs.xcodeproj/project.pbxproj index e143f18..4694e9a 100644 --- a/Twigs.xcodeproj/project.pbxproj +++ b/Twigs.xcodeproj/project.pbxproj @@ -39,7 +39,6 @@ 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 */; }; - 8021EFAD280A0FCA00043F18 /* TwigsCore in Frameworks */ = {isa = PBXBuildFile; productRef = 8021EFAC280A0FCA00043F18 /* TwigsCore */; }; 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 */; }; @@ -59,6 +58,7 @@ 80AC75CD284E8E100099E846 /* EditPasswordView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80AC75CC284E8E100099E846 /* EditPasswordView.swift */; }; 80AC75CF284E8E1B0099E846 /* EditEmailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80AC75CE284E8E1B0099E846 /* EditEmailView.swift */; }; 80AF7A982835ED3B009565C6 /* RecurringTransactionFormView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80AF7A972835ED3B009565C6 /* RecurringTransactionFormView.swift */; }; + 80D06DD1288C817800B50467 /* TwigsCore in Frameworks */ = {isa = PBXBuildFile; productRef = 80D06DD0288C817800B50467 /* TwigsCore */; }; 80D1FC14277C1EF9007F17FB /* InlineLoadingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80D1FC13277C1EF9007F17FB /* InlineLoadingView.swift */; }; 80D2CE1A2833448500EDD6C2 /* DataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80D2CE192833448500EDD6C2 /* DataStore.swift */; }; 80FC1BBE28411DD800682F21 /* YearlyFrequencyPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80FC1BBD28411DD800682F21 /* YearlyFrequencyPicker.swift */; }; @@ -166,7 +166,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 8021EFAD280A0FCA00043F18 /* TwigsCore in Frameworks */, + 80D06DD1288C817800B50467 /* TwigsCore in Frameworks */, 8076A8522809FE99006B9DC9 /* Collections in Frameworks */, 8076A84F2809FE8E006B9DC9 /* ArgumentParser in Frameworks */, ); @@ -413,7 +413,7 @@ packageProductDependencies = ( 8076A84E2809FE8E006B9DC9 /* ArgumentParser */, 8076A8512809FE99006B9DC9 /* Collections */, - 8021EFAC280A0FCA00043F18 /* TwigsCore */, + 80D06DD0288C817800B50467 /* TwigsCore */, ); productName = Budget; productReference = 28AC94EA233C373900BFB70A /* Twigs.app */; @@ -800,7 +800,7 @@ CODE_SIGN_ENTITLEMENTS = Twigs/Twigs.entitlements; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 16; + CURRENT_PROJECT_VERSION = 18; DERIVE_MACCATALYST_PRODUCT_BUNDLE_IDENTIFIER = YES; DEVELOPMENT_ASSET_PATHS = "\"Twigs/Preview Content\""; DEVELOPMENT_TEAM = 9Z6DE6KNJ9; @@ -829,7 +829,7 @@ CODE_SIGN_ENTITLEMENTS = Twigs/Twigs.entitlements; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 16; + CURRENT_PROJECT_VERSION = 18; DERIVE_MACCATALYST_PRODUCT_BUNDLE_IDENTIFIER = YES; DEVELOPMENT_ASSET_PATHS = "\"Twigs/Preview Content\""; DEVELOPMENT_TEAM = 9Z6DE6KNJ9; @@ -1057,10 +1057,6 @@ /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ - 8021EFAC280A0FCA00043F18 /* TwigsCore */ = { - isa = XCSwiftPackageProductDependency; - productName = TwigsCore; - }; 8076A84E2809FE8E006B9DC9 /* ArgumentParser */ = { isa = XCSwiftPackageProductDependency; package = 80A419F12787C13E0090C515 /* XCRemoteSwiftPackageReference "swift-argument-parser" */; @@ -1076,6 +1072,10 @@ package = 80A419F12787C13E0090C515 /* XCRemoteSwiftPackageReference "swift-argument-parser" */; productName = ArgumentParser; }; + 80D06DD0288C817800B50467 /* TwigsCore */ = { + isa = XCSwiftPackageProductDependency; + productName = TwigsCore; + }; /* End XCSwiftPackageProductDependency section */ }; rootObject = 28AC94E2233C373900BFB70A /* Project object */; diff --git a/Twigs/Category/CategoryDetailsView.swift b/Twigs/Category/CategoryDetailsView.swift index 98d8e03..7abcc0c 100644 --- a/Twigs/Category/CategoryDetailsView.swift +++ b/Twigs/Category/CategoryDetailsView.swift @@ -31,7 +31,7 @@ struct CategoryDetailsView: View { return LocalizedStringKey("amount_earned") } } - + var body: some View { if let category = dataStore.selectedCategory { TransactionListView() { @@ -65,7 +65,7 @@ struct CategoryDetailsView: View { }) } } - + init (_ budget: Budget) { self.budget = budget } diff --git a/Twigs/DataStore.swift b/Twigs/DataStore.swift index 549b56b..157569a 100644 --- a/Twigs/DataStore.swift +++ b/Twigs/DataStore.swift @@ -44,7 +44,7 @@ class DataStore : ObservableObject { } } } - + var budgetId: String? { get { if case let .success(budget) = self.budget { @@ -54,7 +54,7 @@ class DataStore : ObservableObject { } } } - + var categoryId: String? { get { if case let .success(category) = self.category { @@ -74,7 +74,7 @@ class DataStore : ObservableObject { self.token = UserDefaults.standard.string(forKey: KEY_TOKEN) self.userId = UserDefaults.standard.string(forKey: KEY_USER_ID) } - + func getBudgets(count: Int? = nil, page: Int? = nil) async { // TODO: Find some way to extract this to a generic function self.budgets = .loading @@ -99,11 +99,11 @@ class DataStore : ObservableObject { showBudgetSelection = true } } - + func newBudget() { self.budget = .editing(Budget(id: "", name: "", description: "", currencyCode: "")) } - + func save(_ budget: Budget) async { self.budget = .saving(budget) do { @@ -123,7 +123,7 @@ class DataStore : ObservableObject { self.budget = .error(error, budget) } } - + func deleteBudget() async { guard case let .editing(budget) = self.budget, budget.id != "" else { return @@ -139,7 +139,7 @@ class DataStore : ObservableObject { self.budget = .error(error, budget) } } - + func cancelEditBudget() async { guard case let .success(budgets) = self.budgets else { return @@ -153,7 +153,7 @@ class DataStore : ObservableObject { } await self.selectBudget(budget) } - + func loadOverview(showLoader: Bool = true) async { guard case let .success(budget) = self.budget else { return @@ -178,7 +178,7 @@ class DataStore : ObservableObject { } else { budgetOverview.expectedIncome += category.amount } - + if category.expense { budgetOverview.actualExpenses += abs(response.balance) } else { @@ -191,7 +191,7 @@ class DataStore : ObservableObject { self.overview = .error(error) } } - + func selectBudget(_ budget: Budget?) async { if let budget = budget { self.budget = .success(budget) @@ -206,7 +206,7 @@ class DataStore : ObservableObject { self.recurringTransactions = .empty } } - + func editBudget() { guard case let .success(budget) = self.budget else { return @@ -225,14 +225,14 @@ class DataStore : ObservableObject { } } @Published var selectedCategory: TwigsCore.Category? = nil - + func getCategories(showLoader: Bool = true) async { guard case let .success(budget) = self.budget else { return } await self.getCategories(budgetId: budget.id, showLoader: showLoader) } - + func getCategories(budgetId: String, expense: Bool? = nil, archived: Bool? = false, count: Int? = nil, page: Int? = nil, showLoader: Bool = true) async { if showLoader { self.categories = .loading @@ -244,7 +244,7 @@ class DataStore : ObservableObject { self.categories = .error(error) } } - + func save(_ category: TwigsCore.Category) async { self.category = .loading do { @@ -265,7 +265,7 @@ class DataStore : ObservableObject { self.category = .error(error, category) } } - + func delete(_ category: TwigsCore.Category) async { self.category = .loading do { @@ -279,12 +279,12 @@ class DataStore : ObservableObject { self.category = .error(error, category) } } - + func edit(_ category: TwigsCore.Category) async { self.editingCategory = true self.category = .editing(category) } - + func cancelEditCategory() { self.editingCategory = false if let category = self.selectedCategory { @@ -313,7 +313,7 @@ class DataStore : ObservableObject { } } @Published var selectedRecurringTransaction: RecurringTransaction? = nil - + func getRecurringTransactions(showLoader: Bool = true) async { guard case let .success(budget) = self.budget else { return @@ -328,7 +328,7 @@ class DataStore : ObservableObject { self.recurringTransactions = .error(error) } } - + func newRecurringTransaction() { guard case let .success(user) = self.currentUser else { return @@ -338,11 +338,11 @@ class DataStore : ObservableObject { } self.recurringTransaction = .editing(RecurringTransaction(createdBy: user.id, budgetId: budget.id)) } - + func edit(_ transaction: RecurringTransaction) async { self.recurringTransaction = .editing(transaction) } - + func cancelEditRecurringTransaction() { guard case let .editing(rt) = self.recurringTransaction else { return @@ -353,7 +353,7 @@ class DataStore : ObservableObject { self.recurringTransaction = .empty } } - + func saveRecurringTransaction(_ transaction: RecurringTransaction) async { self.recurringTransaction = .loading do { @@ -377,7 +377,7 @@ class DataStore : ObservableObject { self.recurringTransactions = .error(error) } } - + func deleteRecurringTransaction(_ transaction: RecurringTransaction) async { self.recurringTransaction = .loading do { @@ -390,7 +390,7 @@ class DataStore : ObservableObject { self.recurringTransaction = .error(error, transaction) } } - + func clearSelectedRecurringTransaction() { self.recurringTransaction = .empty } @@ -406,7 +406,7 @@ class DataStore : ObservableObject { } } @Published var selectedTransaction: Transaction? = nil - + func getTransactions(showLoader: Bool = true) async { guard let budgetId = self.budgetId else { self.transactions = .error(NetworkError.unknown) @@ -434,7 +434,7 @@ class DataStore : ObservableObject { self.transactions = .error(error) } } - + func saveTransaction(_ transaction: Transaction) async { self.transaction = .saving(transaction) do { @@ -454,7 +454,7 @@ class DataStore : ObservableObject { self.transaction = .error(error, transaction) } } - + func deleteTransaction(_ transaction: Transaction) async { self.transaction = .loading do { @@ -465,7 +465,7 @@ class DataStore : ObservableObject { self.transaction = .error(error, transaction) } } - + func newTransaction() { var budgetId = "" if case let .success(budget) = self.budget { @@ -481,7 +481,7 @@ class DataStore : ObservableObject { } self.transaction = .editing(TwigsCore.Transaction(categoryId: categoryId, createdBy: createdBy, budgetId: budgetId)) } - + func editTransaction(_ transaction: Transaction) { self.transaction = .editing(transaction) } @@ -493,11 +493,11 @@ class DataStore : ObservableObject { self.transaction = .empty } } - + func clearSelectedTransaction() { self.transaction = .empty } - + @Published var currentUser: AsyncData = .empty { didSet { switch currentUser { @@ -510,7 +510,7 @@ class DataStore : ObservableObject { } } } - + private let KEY_BASE_URL = "BASE_URL" private let KEY_TOKEN = "TOKEN" private let KEY_USER_ID = "USER_ID" @@ -533,11 +533,11 @@ class DataStore : ObservableObject { } } @Published var showLogin: Bool = true - + func clearUserError() { self.currentUser = .empty } - + func login(username: String, password: String) async { if baseUrl.isEmpty { self.currentUser = .error(NetworkError.invalidUrl) @@ -559,7 +559,7 @@ class DataStore : ObservableObject { self.currentUser = .error(error) } } - + func register(username: String, email: String, password: String, confirmPassword: String) async { if baseUrl.isEmpty { self.currentUser = .error(NetworkError.invalidUrl) @@ -595,7 +595,7 @@ class DataStore : ObservableObject { } await self.login(username: username, password: password) } - + func logout() { self.budgets = .empty self.budget = .empty @@ -615,7 +615,7 @@ class DataStore : ObservableObject { UserDefaults.standard.removeObject(forKey: KEY_TOKEN) UserDefaults.standard.removeObject(forKey: KEY_USER_ID) } - + func loadProfile() async { guard let userId = self.userId, !userId.isEmpty else { return @@ -628,7 +628,7 @@ class DataStore : ObservableObject { self.currentUser = .error(error) } } - + func updateUsername(_ username: String) async -> UsernameError? { guard case let .success(current) = self.currentUser else { return .unknown @@ -643,7 +643,7 @@ class DataStore : ObservableObject { return .unavailable } } - + func updateEmail(_ email: String) async -> EmailError? { guard case let .success(current) = self.currentUser else { return .unknown @@ -661,7 +661,7 @@ class DataStore : ObservableObject { return .unavailable } } - + func updatePassword(_ password: String, confirmPassword: String) async -> PasswordError? { guard case let .success(current) = self.currentUser else { return .unknown diff --git a/Twigs/Transaction/TransactionListView.swift b/Twigs/Transaction/TransactionListView.swift index ecb5fe3..d88824d 100644 --- a/Twigs/Transaction/TransactionListView.swift +++ b/Twigs/Transaction/TransactionListView.swift @@ -24,7 +24,7 @@ struct TransactionListView: View where Content: View { } return false } - + @ViewBuilder private func TransactionList(_ transactions: OrderedDictionary) -> some View { if transactions.isEmpty { @@ -37,10 +37,21 @@ struct TransactionListView: View where Content: View { } ForEach(transactions.keys, id: \.self) { (key: String) in Group { - let filtered = search.isEmpty ? transactions[key]! : transactions[key]!.filter { $0.title.lowercased().contains(search.lowercased()) - || $0.description?.lowercased().contains(search.lowercased()) ?? false - || $0.amount.toCurrencyString().contains(search) - } + let filtered = transactions[key]! + .filter { + if let categoryId = dataStore.selectedCategory?.id { + if $0.categoryId != categoryId { + return false + } + } + if !search.isEmpty { + return $0.title.lowercased().contains(search.lowercased()) + || $0.description?.lowercased().contains(search.lowercased()) ?? false + || $0.amount.toCurrencyString().contains(search) + } + + return true + } if !filtered.isEmpty { Section(header: Text(key)) { ForEach(filtered) { transaction in @@ -52,7 +63,7 @@ struct TransactionListView: View where Content: View { } } } - + private var currentUserId: String? { get { if case let .success(currentUser) = dataStore.currentUser { @@ -62,7 +73,7 @@ struct TransactionListView: View where Content: View { } } } - + private var budgetId: String? { get { if case let .success(budget) = dataStore.budget { @@ -72,16 +83,6 @@ struct TransactionListView: View where Content: View { } } } - - private var categoryId: String? { - get { - if case let .success(category) = dataStore.category { - return category.id - } else { - return nil - } - } - } @ViewBuilder var body: some View { @@ -104,7 +105,7 @@ struct TransactionListView: View where Content: View { dataStore: dataStore, createdBy: currentUserId ?? "", budgetId: budgetId ?? "", - categoryId: categoryId, + categoryId: dataStore.categoryId, transaction: nil )) }) @@ -120,7 +121,7 @@ struct TransactionListView: View where Content: View { ) } } - + init(header: (() -> Content)? = nil) { self.header = header } @@ -129,7 +130,7 @@ struct TransactionListView: View where Content: View { struct TransactionListItemView: View { @EnvironmentObject var dataStore: DataStore var transaction: TwigsCore.Transaction - + var body: some View { NavigationLink( tag: self.transaction, @@ -163,7 +164,7 @@ struct TransactionListItemView: View { } ) } - + init (_ transaction: TwigsCore.Transaction) { self.transaction = transaction }