From 2ec0711bdeb5f8d49e945c22cd496352a37b6915 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CSamoilenkoVadym=E2=80=9D?= <“samoylenko.vadym@gmail.com”> Date: Sun, 2 Mar 2025 18:34:46 +0000 Subject: [PATCH] Add basic app structure with Dashboard, Transactions and Profile views. Create TransactionModel and TransactionRowView --- Coinly/{ => App}/CoinlyApp.swift | 3 ++ Coinly/App/ContentView.swift | 35 ++++++++++++++ Coinly/App/Persistence.swift | 29 ++++++++++++ Coinly/ContentView.swift | 24 ---------- Coinly/Features/Dashboard/DashboardView.swift | 35 ++++++++++++++ Coinly/Features/Models/TransactionModel.swift | 40 ++++++++++++++++ Coinly/Features/Profile/ProfileView.swift | 36 ++++++++++++++ .../Transactions/TransactionsView.swift | 35 ++++++++++++++ Coinly/UI/Components/TransactionRowView.swift | 47 +++++++++++++++++++ .../Coinly.xcdatamodel/contents | 10 ++++ 10 files changed, 270 insertions(+), 24 deletions(-) rename Coinly/{ => App}/CoinlyApp.swift (58%) create mode 100644 Coinly/App/ContentView.swift create mode 100644 Coinly/App/Persistence.swift delete mode 100644 Coinly/ContentView.swift create mode 100644 Coinly/Features/Dashboard/DashboardView.swift create mode 100644 Coinly/Features/Models/TransactionModel.swift create mode 100644 Coinly/Features/Profile/ProfileView.swift create mode 100644 Coinly/Features/Transactions/TransactionsView.swift create mode 100644 Coinly/UI/Components/TransactionRowView.swift create mode 100644 New Group/Coinly/Coinly.xcdatamodeld/Coinly.xcdatamodel/contents diff --git a/Coinly/CoinlyApp.swift b/Coinly/App/CoinlyApp.swift similarity index 58% rename from Coinly/CoinlyApp.swift rename to Coinly/App/CoinlyApp.swift index 8831dcd..576d978 100644 --- a/Coinly/CoinlyApp.swift +++ b/Coinly/App/CoinlyApp.swift @@ -9,9 +9,12 @@ import SwiftUI @main struct CoinlyApp: App { + let persistenceController = PersistenceController.shared + var body: some Scene { WindowGroup { ContentView() + .environment(\.managedObjectContext, persistenceController.container.viewContext) } } } diff --git a/Coinly/App/ContentView.swift b/Coinly/App/ContentView.swift new file mode 100644 index 0000000..c41cb08 --- /dev/null +++ b/Coinly/App/ContentView.swift @@ -0,0 +1,35 @@ +// +// ContentView.swift +// Coinly +// +// Created by Vadym Samoilenko on 02/03/2025. +// + +import SwiftUI + +struct ContentView: View { + var body: some View { + TabView { + DashboardView() + .tabItem { + Label("Dashboard", systemImage: "chart.pie.fill") + } + + TransactionsView() + .tabItem { + Label("Transactions", systemImage: "list.bullet") + } + + ProfileView() + .tabItem { + Label("Profile", systemImage: "person.fill") + } + } + } +} + +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + ContentView() + } +} diff --git a/Coinly/App/Persistence.swift b/Coinly/App/Persistence.swift new file mode 100644 index 0000000..092704b --- /dev/null +++ b/Coinly/App/Persistence.swift @@ -0,0 +1,29 @@ +// +// Persistence.swift +// Coinly +// +// Created by Vadym Samoilenko on 02/03/2025. +// + +import CoreData + +struct PersistenceController { + static let shared = PersistenceController() + + let container: NSPersistentContainer + + init(inMemory: Bool = false) { + container = NSPersistentContainer(name: "Coinly") + + if inMemory { + container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null") + } + + container.loadPersistentStores { (storeDescription, error) in + if let error = error as NSError? { + fatalError("Unresolved error \(error), \(error.userInfo)") + } + } + container.viewContext.automaticallyMergesChangesFromParent = true + } +} diff --git a/Coinly/ContentView.swift b/Coinly/ContentView.swift deleted file mode 100644 index e011825..0000000 --- a/Coinly/ContentView.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// ContentView.swift -// Coinly -// -// Created by Vadym Samoilenko on 02/03/2025. -// - -import SwiftUI - -struct ContentView: View { - var body: some View { - VStack { - Image(systemName: "globe") - .imageScale(.large) - .foregroundStyle(.tint) - Text("Hello, world!") - } - .padding() - } -} - -#Preview { - ContentView() -} diff --git a/Coinly/Features/Dashboard/DashboardView.swift b/Coinly/Features/Dashboard/DashboardView.swift new file mode 100644 index 0000000..f78959a --- /dev/null +++ b/Coinly/Features/Dashboard/DashboardView.swift @@ -0,0 +1,35 @@ +// +// DashboardView.swift +// Coinly +// +// Created by Vadym Samoilenko on 02/03/2025. +// + + +import SwiftUI + +struct DashboardView: View { + var body: some View { + NavigationView { + VStack { + Text("Total Balance") + .font(.subheadline) + .foregroundColor(.gray) + + Text("$1,234.56") + .font(.title) + .fontWeight(.bold) + + Spacer() + } + .padding() + .navigationTitle("Dashboard") + } + } +} + +struct DashboardView_Previews: PreviewProvider { + static var previews: some View { + DashboardView() + } +} \ No newline at end of file diff --git a/Coinly/Features/Models/TransactionModel.swift b/Coinly/Features/Models/TransactionModel.swift new file mode 100644 index 0000000..9e457a7 --- /dev/null +++ b/Coinly/Features/Models/TransactionModel.swift @@ -0,0 +1,40 @@ +// +// TransactionType.swift +// Coinly +// +// Created by Vadym Samoilenko on 02/03/2025. +// + + +import Foundation + +enum TransactionType: String { + case income = "Income" + case expense = "Expense" +} + +struct TransactionModel: Identifiable { + let id = UUID() + var amount: Double + var date: Date + var type: TransactionType + var category: String + var note: String? + + var isExpense: Bool { + type == .expense + } + + var signedAmount: Double { + isExpense ? -amount : amount + } +} + +// Sample Data +extension TransactionModel { + static let sampleData = [ + TransactionModel(amount: 100, date: Date(), type: .income, category: "Salary", note: "Monthly salary"), + TransactionModel(amount: 25.99, date: Date(), type: .expense, category: "Food", note: "Lunch"), + TransactionModel(amount: 50, date: Date(), type: .expense, category: "Transport", note: "Fuel") + ] +} \ No newline at end of file diff --git a/Coinly/Features/Profile/ProfileView.swift b/Coinly/Features/Profile/ProfileView.swift new file mode 100644 index 0000000..724f65c --- /dev/null +++ b/Coinly/Features/Profile/ProfileView.swift @@ -0,0 +1,36 @@ +// +// ProfileView.swift +// Coinly +// +// Created by Vadym Samoilenko on 02/03/2025. +// + + +import SwiftUI + +struct ProfileView: View { + var body: some View { + NavigationView { + List { + Section("Settings") { + Text("Categories") + Text("Currency") + Text("Notifications") + } + + Section("About") { + Text("Help") + Text("Privacy Policy") + Text("Version 1.0") + } + } + .navigationTitle("Profile") + } + } +} + +struct ProfileView_Previews: PreviewProvider { + static var previews: some View { + ProfileView() + } +} \ No newline at end of file diff --git a/Coinly/Features/Transactions/TransactionsView.swift b/Coinly/Features/Transactions/TransactionsView.swift new file mode 100644 index 0000000..d579040 --- /dev/null +++ b/Coinly/Features/Transactions/TransactionsView.swift @@ -0,0 +1,35 @@ +// +// TransactionsView.swift +// Coinly +// +// Created by Vadym Samoilenko on 02/03/2025. +// + + +import SwiftUI + +struct TransactionsView: View { + var body: some View { + NavigationView { + List { + Text("Transaction 1") + Text("Transaction 2") + Text("Transaction 3") + } + .navigationTitle("Transactions") + .toolbar { + Button(action: { + // Add transaction action + }) { + Image(systemName: "plus") + } + } + } + } +} + +struct TransactionsView_Previews: PreviewProvider { + static var previews: some View { + TransactionsView() + } +} \ No newline at end of file diff --git a/Coinly/UI/Components/TransactionRowView.swift b/Coinly/UI/Components/TransactionRowView.swift new file mode 100644 index 0000000..f25bf99 --- /dev/null +++ b/Coinly/UI/Components/TransactionRowView.swift @@ -0,0 +1,47 @@ +// +// TransactionRowView.swift +// Coinly +// +// Created by Vadym Samoilenko on 02/03/2025. +// + + +import SwiftUI + +struct TransactionRowView: View { + let transaction: TransactionModel + + var body: some View { + HStack { + VStack(alignment: .leading) { + Text(transaction.category) + .font(.headline) + if let note = transaction.note { + Text(note) + .font(.subheadline) + .foregroundColor(.gray) + } + } + + Spacer() + + VStack(alignment: .trailing) { + Text(String(format: "%.2f", transaction.amount)) + .font(.headline) + .foregroundColor(transaction.isExpense ? .red : .green) + Text(transaction.date, style: .date) + .font(.caption) + .foregroundColor(.gray) + } + } + .padding(.vertical, 8) + } +} + +struct TransactionRowView_Previews: PreviewProvider { + static var previews: some View { + TransactionRowView(transaction: TransactionModel.sampleData[0]) + .previewLayout(.sizeThatFits) + .padding() + } +} \ No newline at end of file diff --git a/New Group/Coinly/Coinly.xcdatamodeld/Coinly.xcdatamodel/contents b/New Group/Coinly/Coinly.xcdatamodeld/Coinly.xcdatamodel/contents new file mode 100644 index 0000000..697ef59 --- /dev/null +++ b/New Group/Coinly/Coinly.xcdatamodeld/Coinly.xcdatamodel/contents @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file