Add categories with icons and colors for transactions. Update transaction views with new category UI

This commit is contained in:
“SamoilenkoVadym” 2025-03-02 18:49:39 +00:00
parent 9b407e7195
commit 30afdbb5f5
5 changed files with 78 additions and 29 deletions

View file

@ -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")
}

View file

@ -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!
}
}

View file

@ -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 })
}
}

View file

@ -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)
}
}

View file

@ -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()
}
}
}