From 30afdbb5f532dc4a0d8899c1ad4d7ba8b5cf3bb7 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:49:39 +0000 Subject: [PATCH] Add categories with icons and colors for transactions. Update transaction views with new category UI --- Coinly/App/ContentView.swift | 6 ++-- Coinly/Features/Models/CategoryModel.swift | 31 +++++++++++++++++ .../Transactions/AddTransactionView.swift | 18 +++++----- .../Transactions/TransactionsView.swift | 18 ++++------ Coinly/UI/Components/TransactionRowView.swift | 34 ++++++++++++++++--- 5 files changed, 78 insertions(+), 29 deletions(-) create mode 100644 Coinly/Features/Models/CategoryModel.swift diff --git a/Coinly/App/ContentView.swift b/Coinly/App/ContentView.swift index 46ba200..f520263 100644 --- a/Coinly/App/ContentView.swift +++ b/Coinly/App/ContentView.swift @@ -1,16 +1,16 @@ import SwiftUI struct ContentView: View { - @State private var transactions = TransactionModel.sampleData + @StateObject private var transactionsStore = TransactionsStore() var body: some View { TabView { - DashboardView(transactions: transactions) + DashboardView(transactions: transactionsStore.transactions) .tabItem { Label("Dashboard", systemImage: "chart.pie.fill") } - TransactionsView() + TransactionsView(store: transactionsStore) .tabItem { Label("Transactions", systemImage: "list.bullet") } diff --git a/Coinly/Features/Models/CategoryModel.swift b/Coinly/Features/Models/CategoryModel.swift new file mode 100644 index 0000000..2c3d099 --- /dev/null +++ b/Coinly/Features/Models/CategoryModel.swift @@ -0,0 +1,31 @@ +// +// CategoryModel.swift +// Coinly +// +// Created by Vadym Samoilenko on 02/03/2025. +// + + +import Foundation + +struct CategoryModel: Identifiable { + let id = UUID() + let name: String + let icon: String // SF Symbols name + let color: String // Будем хранить как строку +} + +extension CategoryModel { + static let categories = [ + CategoryModel(name: "Food", icon: "cart.fill", color: "red"), + CategoryModel(name: "Transport", icon: "car.fill", color: "blue"), + CategoryModel(name: "Entertainment", icon: "tv.fill", color: "purple"), + CategoryModel(name: "Shopping", icon: "bag.fill", color: "orange"), + CategoryModel(name: "Salary", icon: "dollarsign.circle.fill", color: "green"), + CategoryModel(name: "Other", icon: "square.fill", color: "gray") + ] + + static func category(for name: String) -> CategoryModel { + categories.first { $0.name == name } ?? categories.last! + } +} \ No newline at end of file diff --git a/Coinly/Features/Transactions/AddTransactionView.swift b/Coinly/Features/Transactions/AddTransactionView.swift index a3607da..128450f 100644 --- a/Coinly/Features/Transactions/AddTransactionView.swift +++ b/Coinly/Features/Transactions/AddTransactionView.swift @@ -4,11 +4,10 @@ struct AddTransactionView: View { @Environment(\.dismiss) private var dismiss @State private var amount: String = "" @State private var note: String = "" - @State private var category: String = "Food" + @State private var category: String = CategoryModel.categories[0].name @State private var date = Date() @State private var type: TransactionType = .expense - let categories = ["Food", "Transport", "Entertainment", "Shopping", "Salary", "Other"] let addTransaction: (TransactionModel) -> Void var body: some View { @@ -29,8 +28,13 @@ struct AddTransactionView: View { Section("Details") { Picker("Category", selection: $category) { - ForEach(categories, id: \.self) { category in - Text(category).tag(category) + ForEach(CategoryModel.categories) { category in + HStack { + Image(systemName: category.icon) + .foregroundColor(Color(category.color)) + Text(category.name) + } + .tag(category.name) } } @@ -68,9 +72,3 @@ struct AddTransactionView: View { } } } - -struct AddTransactionView_Previews: PreviewProvider { - static var previews: some View { - AddTransactionView(addTransaction: { _ in }) - } -} diff --git a/Coinly/Features/Transactions/TransactionsView.swift b/Coinly/Features/Transactions/TransactionsView.swift index ff8fad4..173e91d 100644 --- a/Coinly/Features/Transactions/TransactionsView.swift +++ b/Coinly/Features/Transactions/TransactionsView.swift @@ -1,20 +1,18 @@ import SwiftUI struct TransactionsView: View { - @State private var transactions = TransactionModel.sampleData + @ObservedObject var store: TransactionsStore @State private var showingAddTransaction = false - func addTransaction(_ transaction: TransactionModel) { - transactions.insert(transaction, at: 0) - } - var body: some View { NavigationView { List { - ForEach(transactions) { transaction in + ForEach(store.transactions) { transaction in TransactionRowView(transaction: transaction) } - .onDelete(perform: deleteTransactions) + .onDelete { indexSet in + store.deleteTransaction(at: indexSet) + } } .navigationTitle("Transactions") .toolbar { @@ -25,12 +23,8 @@ struct TransactionsView: View { } } .sheet(isPresented: $showingAddTransaction) { - AddTransactionView(addTransaction: addTransaction) + AddTransactionView(addTransaction: store.addTransaction) } } } - - private func deleteTransactions(at offsets: IndexSet) { - transactions.remove(atOffsets: offsets) - } } diff --git a/Coinly/UI/Components/TransactionRowView.swift b/Coinly/UI/Components/TransactionRowView.swift index f25bf99..e19c5b6 100644 --- a/Coinly/UI/Components/TransactionRowView.swift +++ b/Coinly/UI/Components/TransactionRowView.swift @@ -11,9 +11,34 @@ import SwiftUI struct TransactionRowView: View { let transaction: TransactionModel + private var category: CategoryModel { + CategoryModel.category(for: transaction.category) + } + + private var categoryColor: Color { + switch category.color { + case "red": return .red + case "blue": return .blue + case "purple": return .purple + case "orange": return .orange + case "green": return .green + case "gray": return .gray + default: return .gray + } + } + var body: some View { - HStack { - VStack(alignment: .leading) { + HStack(spacing: 12) { + // Category Icon + Image(systemName: category.icon) + .font(.title2) + .foregroundColor(.white) + .frame(width: 40, height: 40) + .background(categoryColor) + .clipShape(RoundedRectangle(cornerRadius: 10)) + + // Transaction Details + VStack(alignment: .leading, spacing: 4) { Text(transaction.category) .font(.headline) if let note = transaction.note { @@ -25,7 +50,8 @@ struct TransactionRowView: View { Spacer() - VStack(alignment: .trailing) { + // Amount and Date + VStack(alignment: .trailing, spacing: 4) { Text(String(format: "%.2f", transaction.amount)) .font(.headline) .foregroundColor(transaction.isExpense ? .red : .green) @@ -44,4 +70,4 @@ struct TransactionRowView_Previews: PreviewProvider { .previewLayout(.sizeThatFits) .padding() } -} \ No newline at end of file +}