Skip to content

Commit

Permalink
Update [Reporting View] & Add CSV Export
Browse files Browse the repository at this point in the history
  • Loading branch information
David200308 committed Sep 12, 2024
1 parent a5ad953 commit 50742a4
Show file tree
Hide file tree
Showing 9 changed files with 139 additions and 85 deletions.
2 changes: 2 additions & 0 deletions Budget.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,7 @@
ENABLE_PREVIEWS = YES;
INFOPLIST_FILE = Budget/Info.plist;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.finance";
IPHONEOS_DEPLOYMENT_TARGET = 16.6;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
Expand All @@ -363,6 +364,7 @@
ENABLE_PREVIEWS = YES;
INFOPLIST_FILE = Budget/Info.plist;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.finance";
IPHONEOS_DEPLOYMENT_TARGET = 16.6;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
{
"originHash" : "d77223ea3cadaebd2154378ec5005b6ebefcef3b34a4dafa368b0c4f16c0561c",
"pins" : [
{
"identity" : "grdb.swift",
"kind" : "remoteSourceControl",
"location" : "https://github.com/groue/GRDB.swift",
"state" : {
"branch" : "master",
"revision" : "d3862c042446d3025a8a4123b013e1b6d58fc315"
"revision" : "2cf6c756e1e5ef6901ebae16576a7e4e4b834622"
}
}
],
"version" : 2
"version" : 3
}
Binary file not shown.
112 changes: 77 additions & 35 deletions Budget/BudgetView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,44 +8,68 @@

import SwiftUI
import GRDB
import UniformTypeIdentifiers

@available(iOS 14.0, *)
@available(iOS 16.0, *)
struct BudgetView: View {
@EnvironmentObject private var stateController: StateController
@State private var addingNewTransaction = false
@EnvironmentObject private var stateController: StateController
@State private var addingNewTransaction = false
@State private var monthReporting = false
// @State private var exportFile = false

var body: some View {
NavigationView {
AccountView(account: stateController.account)
.navigationBarTitle("Budget")
.navigationBarItems(trailing: Button(action: { self.addingNewTransaction = true }) {
Image(systemName: "plus")
.font(.title)
})

.navigationBarItems(trailing: Button(action: { self.monthReporting = true }) {
Image(systemName: "doc.fill")
.font(.title)
.imageScale(.medium)
})

// .navigationBarItems(trailing: Button(action: { self.exportFile = true }) {
// Image(systemName: "square.and.arrow.up")
// .font(.title)
// .imageScale(.medium)
// })

.sheet(isPresented: $addingNewTransaction) {
TransactionView()
.environmentObject(self.stateController)
}
.sheet(isPresented: $monthReporting) {
ReportingView()
.environmentObject(self.stateController)
}
}
@State private var exportFile = false
@State private var csvData: Data? = nil
@State private var showFileExporter = false

var body: some View {
NavigationView {
AccountView(account: stateController.account)
.navigationTitle("Budget")
.toolbar {
ToolbarItemGroup(placement: .navigationBarTrailing) {
Button(action: exportCSV) {
Image(systemName: "square.and.arrow.up")
.font(.title)
.imageScale(.medium)
}

Button(action: { self.monthReporting = true }) {
Image(systemName: "doc.fill")
.font(.title)
.imageScale(.medium)
}

Button(action: { self.addingNewTransaction = true }) {
Image(systemName: "plus")
.font(.title)
}
}
}
.sheet(isPresented: $addingNewTransaction) {
TransactionView()
.environmentObject(self.stateController)
}
.sheet(isPresented: $monthReporting) {
ReportingView()
.environmentObject(self.stateController)
}
.fileExporter(
isPresented: $showFileExporter,
document: CSVDocument(data: csvData ?? Data()),
contentType: .commaSeparatedText,
defaultFilename: "transactions"
) { result in
switch result {
case .success(let url):
print("File saved to: \(url)")
case .failure(let error):
print("Failed to save file: \(error.localizedDescription)")
}
}
}
}

private func exportCSV() {
csvData = stateController.account.exportCSVData()
showFileExporter = csvData != nil
}
}

Expand Down Expand Up @@ -141,6 +165,24 @@ struct Row: View {
}
}

// MARK: - CSV Document
struct CSVDocument: FileDocument {
static var readableContentTypes: [UTType] { [.commaSeparatedText] }
var data: Data

init(data: Data) {
self.data = data
}

init(configuration: ReadConfiguration) throws {
data = configuration.file.regularFileContents ?? Data()
}

func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper {
return .init(regularFileWithContents: data)
}
}

//// MARK: - Previews
//struct BudgetView_Previews: PreviewProvider {
// static let account = TransactionData.account
Expand Down
68 changes: 31 additions & 37 deletions Budget/Model.swift
Original file line number Diff line number Diff line change
Expand Up @@ -185,41 +185,35 @@ struct Account {

}

// mutating func exportCSV() {
// do {
// let dbQueue = try DatabaseQueue(path: fileName())
//
// struct Data: Codable, FetchableRecord, PersistableRecord {
// var id: Int
// var amount: Int
// var date: Date
// var description: String
// var category: String
// var status: Int
// }
//
// let transaction: [Data] = try dbQueue.read { db in
// try Data.fetchAll(db, sql: "SELECT * FROM data WHERE status = 0")
// }
//
// // Create a CSV file path
// let fileURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first?.appendingPathComponent("transactions.csv")
//
// // Prepare the CSV data
// var csvText = "ID,Amount,Date,Description,Category,Status\n"
// for data in transaction {
// let row = "\(data.id),\(data.amount),\(data.date),\(data.description),\(data.category),\(data.status)\n"
// csvText.append(row)
// }
//
// // Write the CSV data to the file
// try csvText.write(to: fileURL!, atomically: true, encoding: .utf8)
//
// print("CSV file exported successfully.")
//
// } catch {
// print(error)
// }
// }
//
mutating func exportCSVData() -> Data? {
do {
let dbQueue = try DatabaseQueue(path: fileName())

struct Data: Codable, FetchableRecord, PersistableRecord {
var id: Int
var amount: Int
var date: Date
var description: String
var category: String
var status: Int
}

let transaction: [Data] = try dbQueue.read { db in
try Data.fetchAll(db, sql: "SELECT * FROM data WHERE status = 1")
}

var csvText = "ID,Amount,Date,Description,Category,Status\n"
for data in transaction {
let row = "\(data.id),\(data.amount),\(data.date),\(data.description),\(data.category),\(data.status)\n"
csvText.append(row)
}

return csvText.data(using: .utf8)

} catch {
print("Failed to export CSV:", error)
return nil
}
}

}
17 changes: 17 additions & 0 deletions Budget/ReportingView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//

import SwiftUI
import Charts
import UniformTypeIdentifiers

struct ReportingView: View {
Expand Down Expand Up @@ -87,7 +88,23 @@ struct ReportContent: View {
@Binding var amount: String
var statistics: [Statistic]

@available(iOS 16.0, *)
var body: some View {
VStack {
GroupBox("Monthly Expense") {
Chart {
ForEach(statistics.filter({ $0.month != "All" })) { data in
BarMark(
x: .value("Month", data.year + " - " + data.month),
y: .value("Expense", data.amount / (-100)),
width: .fixed(20)
)
}
}
}
.padding()
}

List {
ForEach(statistics) { stat in
if stat.month == "All" {
Expand Down
2 changes: 1 addition & 1 deletion Budget/SceneDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import UIKit
import SwiftUI

@available(iOS 14.0, *)
@available(iOS 16.0, *)
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?

Expand Down
6 changes: 3 additions & 3 deletions Budget/TransactionView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import SwiftUI
import UniformTypeIdentifiers

@available(iOS 14.0, *)
@available(iOS 16.0, *)
struct TransactionView: View {
@State private var amount: String = ""
@State private var selectedCategory: Transaction.Category = .groceries
Expand All @@ -33,7 +33,7 @@ struct TransactionView: View {
}
}

@available(iOS 14.0, *)
@available(iOS 16.0, *)
extension TransactionView {
func addTransaction() {
let sign = selectedCategory == .income ? 1.0 : -1.0
Expand Down Expand Up @@ -73,7 +73,7 @@ extension TransactionView {
// }
//}

@available(iOS 14.0, *)
@available(iOS 16.0, *)
struct TransactionContent: View {
@Binding var amount: String
@Binding var selectedCategory: Transaction.Category
Expand Down
12 changes: 5 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
# Budget iOS APP
A Budget APP write by Swift + SwiftUI on iOS

## Language
## Tech Stack

- Swift + SwiftUI

## Database

- SQLite
- Database: SQLite (Maybe switch to SwiftData)

## Functions

- Record user's transactions offline []
- Delete the transaction []
- Export transaction CSV file []
- Delete the transaction []
- Export transaction CSV file []
- Statistic Report [![50%](https://progress-bar.xyz/50)]

0 comments on commit 50742a4

Please sign in to comment.