Use Swift Charts for budget overview actual vs expected
This commit is contained in:
parent
eb50266745
commit
6af0fda86f
7 changed files with 100 additions and 96 deletions
|
@ -492,7 +492,7 @@
|
||||||
isa = PBXProject;
|
isa = PBXProject;
|
||||||
attributes = {
|
attributes = {
|
||||||
LastSwiftUpdateCheck = 1320;
|
LastSwiftUpdateCheck = 1320;
|
||||||
LastUpgradeCheck = 1340;
|
LastUpgradeCheck = 1420;
|
||||||
ORGANIZATIONNAME = "William Brawner";
|
ORGANIZATIONNAME = "William Brawner";
|
||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
28AC94E9233C373900BFB70A = {
|
28AC94E9233C373900BFB70A = {
|
||||||
|
@ -757,7 +757,7 @@
|
||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 16.2;
|
||||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||||
MTL_FAST_MATH = YES;
|
MTL_FAST_MATH = YES;
|
||||||
ONLY_ACTIVE_ARCH = YES;
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
|
@ -814,7 +814,7 @@
|
||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 16.2;
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
MTL_FAST_MATH = YES;
|
MTL_FAST_MATH = YES;
|
||||||
PRODUCT_NAME = "";
|
PRODUCT_NAME = "";
|
||||||
|
@ -834,22 +834,27 @@
|
||||||
CODE_SIGN_ENTITLEMENTS = Twigs/Twigs.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Twigs/Twigs.entitlements;
|
||||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
|
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 19;
|
CURRENT_PROJECT_VERSION = 22;
|
||||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
DERIVE_MACCATALYST_PRODUCT_BUNDLE_IDENTIFIER = YES;
|
DERIVE_MACCATALYST_PRODUCT_BUNDLE_IDENTIFIER = YES;
|
||||||
DEVELOPMENT_ASSET_PATHS = "\"Twigs/Preview Content\"";
|
DEVELOPMENT_ASSET_PATHS = "\"Twigs/Preview Content\"";
|
||||||
DEVELOPMENT_TEAM = 9Z6DE6KNJ9;
|
DEVELOPMENT_TEAM = 9Z6DE6KNJ9;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
INFOPLIST_FILE = Twigs/Info.plist;
|
INFOPLIST_FILE = Twigs/Info.plist;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
INFOPLIST_KEY_CFBundleDisplayName = Twigs;
|
||||||
"IPHONEOS_DEPLOYMENT_TARGET[sdk=macosx*]" = 15.0;
|
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.finance";
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 16.2;
|
||||||
|
"IPHONEOS_DEPLOYMENT_TARGET[sdk=macosx*]" = 16.2;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.wbrawner.projects.budget.ios;
|
PRODUCT_BUNDLE_IDENTIFIER = com.wbrawner.projects.budget.ios;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||||
SUPPORTS_MACCATALYST = YES;
|
SUPPORTS_MACCATALYST = YES;
|
||||||
|
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
TARGETED_DEVICE_FAMILY = "1,2,6";
|
TARGETED_DEVICE_FAMILY = "1,2,6";
|
||||||
};
|
};
|
||||||
|
@ -864,21 +869,26 @@
|
||||||
CODE_SIGN_ENTITLEMENTS = Twigs/Twigs.entitlements;
|
CODE_SIGN_ENTITLEMENTS = Twigs/Twigs.entitlements;
|
||||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
|
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 19;
|
CURRENT_PROJECT_VERSION = 22;
|
||||||
DERIVE_MACCATALYST_PRODUCT_BUNDLE_IDENTIFIER = YES;
|
DERIVE_MACCATALYST_PRODUCT_BUNDLE_IDENTIFIER = YES;
|
||||||
DEVELOPMENT_ASSET_PATHS = "\"Twigs/Preview Content\"";
|
DEVELOPMENT_ASSET_PATHS = "\"Twigs/Preview Content\"";
|
||||||
DEVELOPMENT_TEAM = 9Z6DE6KNJ9;
|
DEVELOPMENT_TEAM = 9Z6DE6KNJ9;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
INFOPLIST_FILE = Twigs/Info.plist;
|
INFOPLIST_FILE = Twigs/Info.plist;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
INFOPLIST_KEY_CFBundleDisplayName = Twigs;
|
||||||
"IPHONEOS_DEPLOYMENT_TARGET[sdk=macosx*]" = 15.0;
|
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.finance";
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 16.2;
|
||||||
|
"IPHONEOS_DEPLOYMENT_TARGET[sdk=macosx*]" = 16.2;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.wbrawner.projects.budget.ios;
|
PRODUCT_BUNDLE_IDENTIFIER = com.wbrawner.projects.budget.ios;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||||
SUPPORTS_MACCATALYST = YES;
|
SUPPORTS_MACCATALYST = YES;
|
||||||
|
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
TARGETED_DEVICE_FAMILY = "1,2,6";
|
TARGETED_DEVICE_FAMILY = "1,2,6";
|
||||||
};
|
};
|
||||||
|
@ -892,7 +902,7 @@
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
DEVELOPMENT_TEAM = 9Z6DE6KNJ9;
|
DEVELOPMENT_TEAM = 9Z6DE6KNJ9;
|
||||||
INFOPLIST_FILE = TwigsTests/Info.plist;
|
INFOPLIST_FILE = TwigsTests/Info.plist;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
|
@ -902,7 +912,7 @@
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Twigs.app/Twigs";
|
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Twigs.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Twigs";
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
};
|
};
|
||||||
|
@ -914,7 +924,7 @@
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
DEVELOPMENT_TEAM = 9Z6DE6KNJ9;
|
DEVELOPMENT_TEAM = 9Z6DE6KNJ9;
|
||||||
INFOPLIST_FILE = TwigsTests/Info.plist;
|
INFOPLIST_FILE = TwigsTests/Info.plist;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
|
@ -924,7 +934,7 @@
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Twigs.app/Twigs";
|
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Twigs.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Twigs";
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
};
|
};
|
||||||
|
@ -942,9 +952,10 @@
|
||||||
);
|
);
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.wbrawner.BudgetUITests;
|
PRODUCT_BUNDLE_IDENTIFIER = com.wbrawner.BudgetUITests;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
PROVISIONING_PROFILE = "";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
TEST_TARGET_NAME = Budget;
|
TEST_TARGET_NAME = Twigs;
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
};
|
};
|
||||||
|
@ -962,9 +973,10 @@
|
||||||
);
|
);
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.wbrawner.BudgetUITests;
|
PRODUCT_BUNDLE_IDENTIFIER = com.wbrawner.BudgetUITests;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
PROVISIONING_PROFILE = "";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
TEST_TARGET_NAME = Budget;
|
TEST_TARGET_NAME = Twigs;
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
};
|
};
|
||||||
|
@ -974,7 +986,8 @@
|
||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||||
CODE_SIGN_IDENTITY = "-";
|
CODE_SIGN_IDENTITY = "-";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
DEVELOPMENT_TEAM = VJ33S6H7W7;
|
DEAD_CODE_STRIPPING = YES;
|
||||||
|
DEVELOPMENT_TEAM = 9Z6DE6KNJ9;
|
||||||
ENABLE_HARDENED_RUNTIME = YES;
|
ENABLE_HARDENED_RUNTIME = YES;
|
||||||
MACOSX_DEPLOYMENT_TARGET = 12.1;
|
MACOSX_DEPLOYMENT_TARGET = 12.1;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
@ -989,7 +1002,8 @@
|
||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||||
CODE_SIGN_IDENTITY = "-";
|
CODE_SIGN_IDENTITY = "-";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
DEVELOPMENT_TEAM = VJ33S6H7W7;
|
DEAD_CODE_STRIPPING = YES;
|
||||||
|
DEVELOPMENT_TEAM = 9Z6DE6KNJ9;
|
||||||
ENABLE_HARDENED_RUNTIME = YES;
|
ENABLE_HARDENED_RUNTIME = YES;
|
||||||
MACOSX_DEPLOYMENT_TARGET = 12.1;
|
MACOSX_DEPLOYMENT_TARGET = 12.1;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Scheme
|
<Scheme
|
||||||
LastUpgradeVersion = "1340"
|
LastUpgradeVersion = "1420"
|
||||||
version = "1.3">
|
version = "1.3">
|
||||||
<BuildAction
|
<BuildAction
|
||||||
parallelizeBuildables = "YES"
|
parallelizeBuildables = "YES"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Scheme
|
<Scheme
|
||||||
LastUpgradeVersion = "1340"
|
LastUpgradeVersion = "1420"
|
||||||
version = "1.3">
|
version = "1.3">
|
||||||
<BuildAction
|
<BuildAction
|
||||||
parallelizeBuildables = "YES"
|
parallelizeBuildables = "YES"
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
// Copyright © 2019 William Brawner. All rights reserved.
|
// Copyright © 2019 William Brawner. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
import Charts
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import TwigsCore
|
import TwigsCore
|
||||||
|
|
||||||
|
@ -21,14 +22,50 @@ struct BudgetDetailsView: View {
|
||||||
errorTextLocalizedStringKey: "budgets_load_failure"
|
errorTextLocalizedStringKey: "budgets_load_failure"
|
||||||
) { overview in
|
) { overview in
|
||||||
List {
|
List {
|
||||||
Section(overview.budget.name) {
|
if let description = overview.budget.description {
|
||||||
DescriptionOverview(overview: overview)
|
Section(overview.budget.name) {
|
||||||
|
Text(description)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Section("income") {
|
|
||||||
IncomeOverview(overview: overview)
|
Section("stats") {
|
||||||
|
HStack {
|
||||||
|
VStack(alignment: .center) {
|
||||||
|
Text("cash_flow")
|
||||||
|
.font(.caption)
|
||||||
|
Text(verbatim: overview.balance.toCurrencyString())
|
||||||
|
.foregroundColor(overview.balance < 0 ? .red : .green)
|
||||||
|
.font(.title2)
|
||||||
|
}
|
||||||
|
Spacer()
|
||||||
|
VStack(alignment: .center) {
|
||||||
|
Text("transactions")
|
||||||
|
.font(.caption)
|
||||||
|
Text(verbatim: String(overview.transactionCount))
|
||||||
|
.font(.title2)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Section("expenses") {
|
Section("expected_vs_actual") {
|
||||||
ExpensesOverview(overview: overview)
|
Chart {
|
||||||
|
BarMark(
|
||||||
|
x: .value("Amount", overview.expectedIncome),
|
||||||
|
y: .value("Label", Bundle.main.localizedString(forKey: "expected_income", value: nil, table: nil))
|
||||||
|
).foregroundStyle(Color.gray)
|
||||||
|
BarMark(
|
||||||
|
x: .value("Amount", overview.actualIncome),
|
||||||
|
y: .value("Label", Bundle.main.localizedString(forKey: "actual_income", value: nil, table: nil))
|
||||||
|
).foregroundStyle(Color.green)
|
||||||
|
BarMark(
|
||||||
|
x: .value("Amount", overview.expectedExpenses),
|
||||||
|
y: .value("Label", Bundle.main.localizedString(forKey: "expected_expenses", value: nil, table: nil))
|
||||||
|
).foregroundStyle(Color.gray)
|
||||||
|
BarMark(
|
||||||
|
x: .value("Amount", overview.actualExpenses),
|
||||||
|
y: .value("Label", Bundle.main.localizedString(forKey: "actual_expenses", value: nil, table: nil))
|
||||||
|
).foregroundStyle(Color.red)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.listStyle(.insetGrouped)
|
.listStyle(.insetGrouped)
|
||||||
|
@ -61,63 +98,6 @@ struct BudgetDetailsView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DescriptionOverview: View {
|
|
||||||
let overview: BudgetOverview
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
VStack(alignment: .leading) {
|
|
||||||
if let description = overview.budget.description {
|
|
||||||
Text(description)
|
|
||||||
}
|
|
||||||
HStack {
|
|
||||||
Text("current_balance")
|
|
||||||
Text(verbatim: overview.balance.toCurrencyString())
|
|
||||||
.foregroundColor(overview.balance < 0 ? .red : .green)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct IncomeOverview: View {
|
|
||||||
let overview: BudgetOverview
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
VStack(alignment: .leading) {
|
|
||||||
HStack {
|
|
||||||
Text("expected")
|
|
||||||
Text(verbatim: overview.expectedIncome.toCurrencyString())
|
|
||||||
}
|
|
||||||
ProgressView(value: Float(overview.expectedIncome), maxValue: overview.maxValue, progressTintColor: .gray, progressBarHeight: 10.0, progressBarCornerRadius: 4.0)
|
|
||||||
HStack {
|
|
||||||
Text("actual")
|
|
||||||
Text(verbatim: overview.actualIncome.toCurrencyString())
|
|
||||||
.foregroundColor(.green)
|
|
||||||
}
|
|
||||||
ProgressView(value: Float(overview.actualIncome), maxValue: overview.maxValue, progressTintColor: .green, progressBarHeight: 10.0, progressBarCornerRadius: 4.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ExpensesOverview: View {
|
|
||||||
let overview: BudgetOverview
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
VStack(alignment: .leading) {
|
|
||||||
HStack {
|
|
||||||
Text("expected")
|
|
||||||
Text(verbatim: overview.expectedExpenses.toCurrencyString())
|
|
||||||
}
|
|
||||||
ProgressView(value: Float(overview.expectedExpenses), maxValue: overview.maxValue, progressTintColor: .gray, progressBarHeight: 10.0, progressBarCornerRadius: 4.0)
|
|
||||||
HStack {
|
|
||||||
Text("actual")
|
|
||||||
Text(verbatim: overview.actualExpenses.toCurrencyString())
|
|
||||||
.foregroundColor(.red)
|
|
||||||
}
|
|
||||||
ProgressView(value: Float(overview.actualExpenses), maxValue: overview.maxValue, progressTintColor: .red, progressBarHeight: 10.0, progressBarCornerRadius: 4.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
struct BudgetDetailsView_Previews: PreviewProvider {
|
struct BudgetDetailsView_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
|
|
|
@ -178,7 +178,12 @@ class DataStore : ObservableObject {
|
||||||
do {
|
do {
|
||||||
let budgetBalance = try await self.apiService.sumTransactions(budgetId: budget.id, categoryId: nil, from: nil, to: nil)
|
let budgetBalance = try await self.apiService.sumTransactions(budgetId: budget.id, categoryId: nil, from: nil, to: nil)
|
||||||
let categories = try await self.apiService.getCategories(budgetId: budget.id, expense: nil, archived: false, count: nil, page: nil)
|
let categories = try await self.apiService.getCategories(budgetId: budget.id, expense: nil, archived: false, count: nil, page: nil)
|
||||||
var budgetOverview = BudgetOverview(budget: budget, balance: budgetBalance.balance)
|
await self.getTransactions(showLoader: false)
|
||||||
|
var transactionCount = 0
|
||||||
|
if case let .success(transactions) = self.transactions {
|
||||||
|
transactionCount = transactions.count
|
||||||
|
}
|
||||||
|
var budgetOverview = BudgetOverview(budget: budget, balance: budgetBalance.balance, categories: categories, transactionCount: transactionCount)
|
||||||
try await withThrowingTaskGroup(of: (TwigsCore.Category, BalanceResponse).self) { group in
|
try await withThrowingTaskGroup(of: (TwigsCore.Category, BalanceResponse).self) { group in
|
||||||
for category in categories {
|
for category in categories {
|
||||||
group.addTask {
|
group.addTask {
|
||||||
|
@ -188,15 +193,15 @@ class DataStore : ObservableObject {
|
||||||
|
|
||||||
for try await (category, response) in group {
|
for try await (category, response) in group {
|
||||||
if category.expense {
|
if category.expense {
|
||||||
budgetOverview.expectedExpenses += category.amount
|
budgetOverview.expectedExpenses += Float(category.amount) / 100.0
|
||||||
} else {
|
} else {
|
||||||
budgetOverview.expectedIncome += category.amount
|
budgetOverview.expectedIncome += Float(category.amount) / 100.0
|
||||||
}
|
}
|
||||||
|
|
||||||
if category.expense {
|
if category.expense {
|
||||||
budgetOverview.actualExpenses += abs(response.balance)
|
budgetOverview.actualExpenses += Float(abs(response.balance)) / 100.0
|
||||||
} else {
|
} else {
|
||||||
budgetOverview.actualIncome += response.balance
|
budgetOverview.actualIncome += Float(response.balance) / 100.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,10 +66,13 @@
|
||||||
"budgets" = "Budgets";
|
"budgets" = "Budgets";
|
||||||
"new_budget" = "New Budget";
|
"new_budget" = "New Budget";
|
||||||
"current_balance" = "Current Balance:";
|
"current_balance" = "Current Balance:";
|
||||||
"expected" = "Expected:";
|
"stats" = "Stats";
|
||||||
"actual" = "Actual:";
|
"cash_flow" = "Cash Flow";
|
||||||
"income" = "Income:";
|
"expected_vs_actual" = "Expected vs Actual";
|
||||||
"expenses" = "Expenses:";
|
"expected_income" = "Expected Income";
|
||||||
|
"expected_expenses" = "Expected Expenses";
|
||||||
|
"actual_income" = "Actual Income";
|
||||||
|
"actual_expenses" = "Actual Expenses";
|
||||||
|
|
||||||
// MARK: Profile
|
// MARK: Profile
|
||||||
"profile" = "Profile";
|
"profile" = "Profile";
|
||||||
|
|
|
@ -65,11 +65,13 @@
|
||||||
"budget" = "Presupuesto";
|
"budget" = "Presupuesto";
|
||||||
"budgets" = "Presupuestos";
|
"budgets" = "Presupuestos";
|
||||||
"new_budget" = "Nuevo Presupuesto";
|
"new_budget" = "Nuevo Presupuesto";
|
||||||
"current_balance" = "Saldo Actual:";
|
"stats" = "Estadísticas";
|
||||||
"income" = "Ingresos:";
|
"cash_flow" = "Flujo de dinero";
|
||||||
"expenses" = "Gastos:";
|
"expected_vs_actual" = "Planeado vs Actual";
|
||||||
"expected" = "Planeados:";
|
"expected_income" = "Ingresos Planeados";
|
||||||
"actual" = "Actuales:";
|
"expected_expenses" = "Gastos Planeados";
|
||||||
|
"actual_income" = "Ingresos Actuales";
|
||||||
|
"actual_expenses" = "Gastos Actuales";
|
||||||
|
|
||||||
|
|
||||||
// MARK: Profile
|
// MARK: Profile
|
||||||
|
|
Loading…
Reference in a new issue