Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Monthly recurring expenses and income #30

Open
wants to merge 12 commits into
base: dev
Choose a base branch
from
Prev Previous commit
Next Next commit
ui for monthly transactions view
comhendrik committed Jun 2, 2022
commit c120265757f5f5e0f42569895137ccbe72ca43d5
Binary file modified .DS_Store
Binary file not shown.
30 changes: 23 additions & 7 deletions Expenso.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
@@ -7,7 +7,9 @@
objects = {

/* Begin PBXBuildFile section */
24AE70432847F81100B2BD49 /* MonthlyExpenseSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24AE70422847F81100B2BD49 /* MonthlyExpenseSettingsView.swift */; };
243DEC7A2848FCC1001281AD /* MonthlyTransactionDetailedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 243DEC792848FCC1001281AD /* MonthlyTransactionDetailedView.swift */; };
243DEC7C2848FF55001281AD /* MonthlyTransactionDetailedViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 243DEC7B2848FF55001281AD /* MonthlyTransactionDetailedViewModel.swift */; };
24AE70432847F81100B2BD49 /* MonthlyTransactionSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24AE70422847F81100B2BD49 /* MonthlyTransactionSettingsView.swift */; };
24DF38B62846B7BC006CA05F /* MonthlyExpenseCD.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24DF38B52846B7BC006CA05F /* MonthlyExpenseCD.swift */; };
736C720A25CFD89900720DEA /* empty-face.json in Resources */ = {isa = PBXBuildFile; fileRef = 736C720925CFD89900720DEA /* empty-face.json */; };
736C721B25CFE8E200720DEA /* LottieView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 736C721A25CFE8E200720DEA /* LottieView.swift */; };
@@ -55,7 +57,9 @@

/* Begin PBXFileReference section */
1B0E373FB89DD0864398FEE7 /* Pods_Expenso.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Expenso.framework; sourceTree = BUILT_PRODUCTS_DIR; };
24AE70422847F81100B2BD49 /* MonthlyExpenseSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MonthlyExpenseSettingsView.swift; sourceTree = "<group>"; };
243DEC792848FCC1001281AD /* MonthlyTransactionDetailedView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MonthlyTransactionDetailedView.swift; sourceTree = "<group>"; };
243DEC7B2848FF55001281AD /* MonthlyTransactionDetailedViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MonthlyTransactionDetailedViewModel.swift; sourceTree = "<group>"; };
24AE70422847F81100B2BD49 /* MonthlyTransactionSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MonthlyTransactionSettingsView.swift; sourceTree = "<group>"; };
24DF38B52846B7BC006CA05F /* MonthlyExpenseCD.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MonthlyExpenseCD.swift; sourceTree = "<group>"; };
2C2D1600DAC62FA04EDCF170 /* Pods-Expenso.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Expenso.debug.xcconfig"; path = "Target Support Files/Pods-Expenso/Pods-Expenso.debug.xcconfig"; sourceTree = "<group>"; };
736C720925CFD89900720DEA /* empty-face.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "empty-face.json"; sourceTree = "<group>"; };
@@ -116,18 +120,28 @@
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
24AE70412847F7F900B2BD49 /* MonthlyExpensesSettings */ = {
243DEC762848FB45001281AD /* MonthlyTransactionSettings */ = {
isa = PBXGroup;
children = (
24AE70422847F81100B2BD49 /* MonthlyExpenseSettingsView.swift */,
24AE70422847F81100B2BD49 /* MonthlyTransactionSettingsView.swift */,
);
path = MonthlyExpensesSettings;
path = MonthlyTransactionSettings;
sourceTree = "<group>";
};
243DEC782848FCAB001281AD /* MonthlyTransactionDetailed */ = {
isa = PBXGroup;
children = (
243DEC792848FCC1001281AD /* MonthlyTransactionDetailedView.swift */,
243DEC7B2848FF55001281AD /* MonthlyTransactionDetailedViewModel.swift */,
);
path = MonthlyTransactionDetailed;
sourceTree = "<group>";
};
733763A827120DB600AA983A /* Screens */ = {
isa = PBXGroup;
children = (
24AE70412847F7F900B2BD49 /* MonthlyExpensesSettings */,
243DEC782848FCAB001281AD /* MonthlyTransactionDetailed */,
243DEC762848FB45001281AD /* MonthlyTransactionSettings */,
739DFF7925DC1E23005BD5C8 /* Authenticate */,
738B1C8E25C680C50067407B /* About */,
738B1C8925C67D790067407B /* ExpenseFilter */,
@@ -464,9 +478,10 @@
files = (
738B1C3825C661750067407B /* ExpenseView.swift in Sources */,
73998C5525DA5578007D735B /* AttachmentHandler.swift in Sources */,
243DEC7A2848FCC1001281AD /* MonthlyTransactionDetailedView.swift in Sources */,
738B1C8425C6764B0067407B /* ExpenseDetailedViewModel.swift in Sources */,
738B1C9025C680D20067407B /* AboutView.swift in Sources */,
24AE70432847F81100B2BD49 /* MonthlyExpenseSettingsView.swift in Sources */,
24AE70432847F81100B2BD49 /* MonthlyTransactionSettingsView.swift in Sources */,
738B1C4F25C663180067407B /* DateExtension.swift in Sources */,
738B1C5225C6632F0067407B /* HelperMethods.swift in Sources */,
738B1C2425C65E060067407B /* Expenso.xcdatamodeld in Sources */,
@@ -490,6 +505,7 @@
738B1C2F25C65EF70067407B /* Configs.swift in Sources */,
73E688DA25FF32790000462A /* ChartView.swift in Sources */,
736C721B25CFE8E200720DEA /* LottieView.swift in Sources */,
243DEC7C2848FF55001281AD /* MonthlyTransactionDetailedViewModel.swift in Sources */,
738B1C7725C675200067407B /* AddExpenseView.swift in Sources */,
738B1C8025C6763E0067407B /* ExpenseDetailedView.swift in Sources */,
);
18 changes: 10 additions & 8 deletions Expenso/Screens/AddExpense/AddExpenseView.swift
Original file line number Diff line number Diff line change
@@ -158,14 +158,16 @@ struct AddExpenseView: View {
VStack {
Spacer()
VStack {
Button(action: { viewModel.saveMonthlyTransaction(managedObjectContext: managedObjectContext) }, label: {
HStack {
Spacer()
TextView(text: "\(viewModel.getButtText()) every Month", type: .button).foregroundColor(.white)
Spacer()
}
})
.padding(.vertical, 12).background(Color.main_color).cornerRadius(8)
if viewModel.expenseObj == nil {
Button(action: { viewModel.saveMonthlyTransaction(managedObjectContext: managedObjectContext) }, label: {
HStack {
Spacer()
TextView(text: "\(viewModel.getButtText()) every Month", type: .button).foregroundColor(.white)
Spacer()
}
})
.padding(.vertical, 12).background(Color.main_color).cornerRadius(8)
}
Button(action: { viewModel.saveTransaction(managedObjectContext: managedObjectContext) }, label: {
HStack {
Spacer()
14 changes: 11 additions & 3 deletions Expenso/Screens/AddExpense/AddExpenseViewModel.swift
Original file line number Diff line number Diff line change
@@ -11,7 +11,7 @@ import CoreData
class AddExpenseViewModel: ObservableObject {

var expenseObj: ExpenseCD?
var monthlyExpenseObj: MonthlyExpenseCD?
var monthlyTransactionObj: MonthlyExpenseCD?

@Published var title = ""
@Published var amount = ""
@@ -168,9 +168,9 @@ class AddExpenseViewModel: ObservableObject {
return
}

if monthlyExpenseObj != nil {
if monthlyTransactionObj != nil {

expense = monthlyExpenseObj!
expense = monthlyTransactionObj!

// if let image = imageAttached {
// if imageUpdated {
@@ -204,6 +204,14 @@ class AddExpenseViewModel: ObservableObject {
} catch { alertMsg = "\(error)"; showAlert = true }
}

func deleteMonthlyTransaction(managedObjectContext: NSManagedObjectContext) {
guard let monthlyTransactionObj = monthlyTransactionObj else { return }
managedObjectContext.delete(monthlyTransactionObj)
do {
try managedObjectContext.save(); closePresenter = true
} catch { alertMsg = "\(error)"; showAlert = true }
}

func checkAllMonthlyExpenses(managedObjectContext: NSManagedObjectContext, request: NSFetchRequest<MonthlyExpenseCD>) {
do {
let allMonthlyExpenses = try? managedObjectContext.fetch(request)
6 changes: 3 additions & 3 deletions Expenso/Screens/Expense/ExpenseView.swift
Original file line number Diff line number Diff line change
@@ -20,7 +20,7 @@ struct ExpenseView: View {
@State private var showOptionsSheet = false
@State private var displayAbout = false
@State private var displaySettings = false
@State private var displayMonthlyExpenses = false
@State private var displayMonthlyTransaction = false


var body: some View {
@@ -31,7 +31,7 @@ struct ExpenseView: View {
VStack {
NavigationLink(destination: NavigationLazyView(ExpenseSettingsView()), isActive: $displaySettings, label: {})
NavigationLink(destination: NavigationLazyView(AboutView()), isActive: $displayAbout, label: {})
NavigationLink(destination: NavigationLazyView(MonthlyExpenseSettingsView()), isActive: $displayMonthlyExpenses, label: {})
NavigationLink(destination: NavigationLazyView(MonthlyTransactionSettingsView()), isActive: $displayMonthlyTransaction, label: {})
ToolbarModelView(title: "Dashboard", hasBackButt: false, button1Icon: IMAGE_OPTION_ICON, button2Icon: IMAGE_FILTER_ICON) { self.presentationMode.wrappedValue.dismiss() }
button1Method: { self.showOptionsSheet = true }
button2Method: { self.showFilterSheet = true }
@@ -48,7 +48,7 @@ struct ExpenseView: View {
ActionSheet(title: Text("Select an option"), buttons: [
.default(Text("About")) { self.displayAbout = true },
.default(Text("Settings")) { self.displaySettings = true },
.default(Text("Monthly Expenses")) { self.displayMonthlyExpenses = true },
.default(Text("Monthly Transactions")) { self.displayMonthlyTransaction = true },
.cancel()
])
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
//
// MonthlyTransactionDetailedView.swift
// Expenso
//
// Created by Hendrik Steen on 02.06.22.
//

import SwiftUI

struct MonthlyTransactionDetailedView: View {

@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
// CoreData
@Environment(\.managedObjectContext) var managedObjectContext

@ObservedObject private var viewModel: MonthlyTransactionDetailedViewModel
@AppStorage(UD_EXPENSE_CURRENCY) var CURRENCY: String = ""

@State private var confirmDelete = false

init(monthlyTransactionObj: MonthlyExpenseCD) {
viewModel = MonthlyTransactionDetailedViewModel(monthlyTransactionObj: monthlyTransactionObj)
}

var body: some View {
NavigationView {
ZStack {
Color.primary_color.edgesIgnoringSafeArea(.all)

VStack {

ToolbarModelView(title: "Details", button1Icon: IMAGE_DELETE_ICON, button2Icon: IMAGE_SHARE_ICON) { self.presentationMode.wrappedValue.dismiss() }
button1Method: { self.confirmDelete = true }
button2Method: { viewModel.shareNote() }

ScrollView(showsIndicators: false) {

VStack(spacing: 24) {
ExpenseDetailedListView(title: "Title", description: viewModel.monthlyTransactionObj.title ?? "")
ExpenseDetailedListView(title: "Amount", description: "\(CURRENCY)\(viewModel.monthlyTransactionObj.amount)")
ExpenseDetailedListView(title: "Transaction type", description: viewModel.monthlyTransactionObj.type == TRANS_TYPE_INCOME ? "Income" : "Expense" )
ExpenseDetailedListView(title: "Tag", description: getTransTagTitle(transTag: viewModel.monthlyTransactionObj.tag ?? ""))
ExpenseDetailedListView(title: "When", description: getDateFormatter(date: viewModel.monthlyTransactionObj.usingDate, format: "EEEE, dd MMM hh:mm a"))
if let note = viewModel.monthlyTransactionObj.note, note != "" {
ExpenseDetailedListView(title: "Note", description: note)
}
if let data = viewModel.monthlyTransactionObj.imageAttached {
VStack(spacing: 8) {
HStack { TextView(text: "Attachment", type: .caption).foregroundColor(Color.init(hex: "828282")); Spacer() }
Image(uiImage: UIImage(data: data)!)
.resizable()
.scaledToFill()
.frame(height: 250).frame(maxWidth: .infinity)
.background(Color.secondary_color)
.cornerRadius(4)
}
}
}.padding(16)

Spacer().frame(height: 24)
Spacer()
}
.alert(isPresented: $confirmDelete,
content: {
Alert(title: Text(APP_NAME), message: Text("Are you sure you want to delete this transaction?"),
primaryButton: .destructive(Text("Delete")) {
viewModel.deleteNote(managedObjectContext: managedObjectContext)
}, secondaryButton: Alert.Button.cancel(Text("Cancel"), action: { confirmDelete = false })
)
})
}.edgesIgnoringSafeArea(.all)
//TODO: Edit View for Monthly Expense
// VStack {
// Spacer()
// HStack {
// Spacer()
// NavigationLink(destination: EditMonthlyTransactionView(viewModel: AddExpenseViewModel(expenseObj: nil, monthlyTransactionObj: viewModel.monthlyTransactionObj)), label: {
// Image("pencil_icon").resizable().frame(width: 28.0, height: 28.0)
// Text("Edit").modifier(InterFont(.semiBold, size: 18)).foregroundColor(.white)
// })
// .padding(EdgeInsets(top: 10, leading: 15, bottom: 10, trailing: 20))
// .background(Color.main_color).cornerRadius(25)
// }.padding(24)
// }
}
.navigationBarHidden(true)
}
.navigationViewStyle(StackNavigationViewStyle())
.navigationBarHidden(true)
.navigationBarBackButtonHidden(true)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//
// MonthlyTransactionDetailedViewModel.swift
// Expenso
//
// Created by Hendrik Steen on 02.06.22.
//

import UIKit
import CoreData

class MonthlyTransactionDetailedViewModel: ObservableObject {

@Published var monthlyTransactionObj: MonthlyExpenseCD

@Published var alertMsg = String()
@Published var showAlert = false
@Published var closePresenter = false

init(monthlyTransactionObj: MonthlyExpenseCD) {
self.monthlyTransactionObj = monthlyTransactionObj
}

func deleteNote(managedObjectContext: NSManagedObjectContext) {
managedObjectContext.delete(monthlyTransactionObj)
do {
try managedObjectContext.save(); closePresenter = true
} catch { alertMsg = "\(error)"; showAlert = true }
}

func shareNote() {
let shareStr = """
Title: \(monthlyTransactionObj.title ?? "")
Amount: \(UserDefaults.standard.string(forKey: UD_EXPENSE_CURRENCY) ?? "")\(monthlyTransactionObj.amount)
monthlyTransactionObj Category: \(getTransTagTitle(transTag: monthlyTransactionObj.tag ?? ""))
Date to charge: \(getDateFormatter(date: monthlyTransactionObj.usingDate, format: "EEEE, dd MMM hh:mm a"))
Note: \(monthlyTransactionObj.note ?? "")

\(SHARED_FROM_EXPENSO)
"""
let av = UIActivityViewController(activityItems: [shareStr], applicationActivities: nil)
UIApplication.shared.windows.first?.rootViewController?.present(av, animated: true, completion: nil)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
//
// MonthlyTransactionSettingsView.swift
// Expenso
//
// Created by Hendrik Steen on 01.06.22.
//

import SwiftUI

struct MonthlyTransactionSettingsView: View {
@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>

@FetchRequest(fetchRequest: MonthlyExpenseCD.getAllMonthlyExpenseData()) var monthlyTransactions: FetchedResults<MonthlyExpenseCD>
var body: some View {
NavigationView {
ZStack {
Color.primary_color.edgesIgnoringSafeArea(.all)

VStack {
ToolbarModelView(title: "Monthly Transaction") { self.presentationMode.wrappedValue.dismiss() }
ScrollView {
ForEach(self.monthlyTransactions) { monthlyTransactionObj in
NavigationLink(destination: MonthlyTransactionDetailedView(monthlyTransactionObj: monthlyTransactionObj), label: { MonthlyTransView(monthlyTransactionObj: monthlyTransactionObj) })
}

}
.padding(.horizontal, 8)
}.edgesIgnoringSafeArea(.all)
}
.navigationBarHidden(true)

}
.navigationViewStyle(StackNavigationViewStyle())
.navigationBarHidden(true)
.navigationBarBackButtonHidden(true)

}

}

struct MonthlyTransView: View {

@ObservedObject var monthlyTransactionObj: MonthlyExpenseCD
@AppStorage(UD_EXPENSE_CURRENCY) var CURRENCY: String = ""

var body: some View {
HStack {

NavigationLink(destination: NavigationLazyView(ExpenseFilterView(categTag: monthlyTransactionObj.tag)), label: {
Image(getTransTagIcon(transTag: monthlyTransactionObj.tag ?? ""))
.resizable().frame(width: 24, height: 24).padding(16)
.background(Color.primary_color).cornerRadius(4)
})

VStack(alignment: .leading, spacing: 6) {
HStack {
TextView(text: monthlyTransactionObj.title ?? "", type: .subtitle_1, lineLimit: 1).foregroundColor(Color.text_primary_color)
Spacer()
TextView(text: "\(monthlyTransactionObj.type == TRANS_TYPE_INCOME ? "+" : "-")\(CURRENCY)\(monthlyTransactionObj.amount)", type: .subtitle_1)
.foregroundColor(monthlyTransactionObj.type == TRANS_TYPE_INCOME ? Color.main_green : Color.main_red)
}
HStack {
TextView(text: getTransTagTitle(transTag: monthlyTransactionObj.tag ?? ""), type: .body_2).foregroundColor(Color.text_primary_color)
Spacer()
TextView(text: "made on: ", type: .body_2).foregroundColor(Color.text_primary_color)
TextView(text: getDateFormatter(date: monthlyTransactionObj.usingDate, format: "MMM dd, yyyy"), type: .body_2).foregroundColor(Color.text_primary_color)
}
}.padding(.leading, 4)

Spacer()

}.padding(8).background(Color.secondary_color).cornerRadius(4)
}
}