Spending Tracker

Spending Tracker

by dockui

Track your expenses effortlessly with this intuitive template. Simple, sleek design to help users monitor their finances with ease. Perfect for budgeting apps!

Platform
SwiftUI
Code
Native Swift
Format
Screen
Access
Free

Code Snippet

import SwiftUI
import Charts

struct Transaction: Identifiable {
    let id = UUID()
    let title: String
    let amount: Double
    let category: TransactionCategory
    let date: Date
    let isIncome: Bool
}

struct FinancialMetric: Identifiable {
    let id = UUID()
    let title: String
    let value: Double
    let trend: Double // Percentage change
    let icon: String
    let color: Color
}

enum TransactionCategory: String {
    case food = "Food & Dining"
    case shopping = "Shopping"
    case transport = "Transport"
    case utilities = "Utilities"
    case entertainment = "Entertainment"
    case income = "Income"
    
    var icon: String {
        switch self {
        case .food: "fork.knife"
        case .shopping: "cart.fill"
        case .transport: "car.fill"
        case .utilities: "bolt.fill"
        case .entertainment: "tv.fill"
        case .income: "dollarsign.circle.fill"
        }
    }
    
    var color: Color {
        switch self {
        case .food: .orange
        case .shopping: .blue
        case .transport: .green
        case .utilities: .purple
        case .entertainment: .pink
        case .income: .mint
        }
    }
}

struct BalanceHistory: Identifiable {
    let id = UUID()
    let date: Date
    let balance: Double
}

struct FinanceDashboardView: View {
    // Dummy Data
    let metrics = [
        FinancialMetric(title: "Total Balance", value: 12450.80, trend: 2.5, icon: "dollarsign.circle.fill", color: .blue),
        FinancialMetric(title: "Income", value: 4500.00, trend: 5.2, icon: "arrow.down.circle.fill", color: .green),
        FinancialMetric(title: "Expenses", value: 2300.50, trend: -1.8, icon: "arrow.up.circle.fill", color: .red)
    ]
    
    let transactions = [
        Transaction(title: "Grocery Store", amount: 85.50, category: .food, date: Date(), isIncome: false),
        Transaction(title: "Salary Deposit", amount: 4500.00, category: .income, date: Date().addingTimeInterval(-86400), isIncome: true),
        Transaction(title: "Netflix", amount: 15.99, category: .entertainment, date: Date().addingTimeInterval(-172800), isIncome: false),
        Transaction(title: "Uber Ride", amount: 24.50, category: .transport, date: Date().addingTimeInterval(-259200), isIncome: false)
    ]
    
    let monthlySpending: [(category: TransactionCategory, amount: Double)] = [
        (.food, 450.0),
        (.shopping, 320.0),
        (.transport, 180.0),
        (.utilities, 250.0),
        (.entertainment, 150.0)
    ]
    
    let balanceHistory: [BalanceHistory] = (0..<7).map { days in
        BalanceHistory(
            date: Date().addingTimeInterval(-Double(days) * 86400),
            balance: Double.random(in: 10000...13000)
        )
    }
    
    var body: some View {
        NavigationStack {
            ScrollView {
                VStack(spacing: 24) {
                    metricsGrid
                    balanceChart
                    spendingBreakdown
                    recentTransactions
                }
                .padding()
            }
            .navigationTitle("Finance")
            .toolbar {
                ToolbarItem(placement: .topBarTrailing) {
                    Button(action: {}) {
                        Image(systemName: "bell.badge")
                            .symbolRenderingMode(.multicolor)
                            .font(.title3)
                    }
                }
            }
        }
    }
    
    private var metricsGrid: some View {
        LazyVGrid(columns: [
            GridItem(.flexible()),
            GridItem(.flexible())
        ], spacing: 16) {
            ForEach(metrics) { metric in
                MetricCard(metric: metric)
            }
        }
    }
    
    private var balanceChart: some View {
        VStack(alignment: .leading, spacing: 16) {
            Text("Balance History")
                .font(.title3)
                .fontWeight(.semibold)
            
            Chart {
                ForEach(balanceHistory) { history in
                    LineMark(
                        x: .value("Date", history.date),
                        y: .value("Balance", history.balance)
                    )
                    .foregroundStyle(Color.blue.gradient)
                    
                    AreaMark(
                        x: .value("Date", history.date),
                        y: .value("Balance", history.balance)
                    )
                    .foregroundStyle(Color.blue.opacity(0.1))
                }
            }
            .frame(height: 200)
        }
        .padding()
        .background(Color(.systemBackground))
        .clipShape(RoundedRectangle(cornerRadius: 15))
        .shadow(color: .black.opacity(0.1), radius: 5)
    }
    
    private var spendingBreakdown: some View {
        VStack(alignment: .leading, spacing: 16) {
            Text("Spending Breakdown")
                .font(.title3)
                .fontWeight(.semibold)
            
            Chart {
                ForEach(monthlySpending, id: \.category) { item in
                    SectorMark(
                        angle: .value("Amount", item.amount),
                        innerRadius: .ratio(0.618),
                        angularInset: 1.5
                    )
                    .cornerRadius(5)
                    .foregroundStyle(item.category.color)
                }
            }
            .frame(height: 200)
            
            // Legend
            VStack(spacing: 8) {
                ForEach(monthlySpending, id: \.category) { item in
                    HStack {
                        Circle()
                            .fill(item.category.color)
                            .frame(width: 8, height: 8)
                        Text(item.category.rawValue)
                            .font(.caption)
                        Spacer()
                        Text("$\(item.amount, specifier: "%.2f")")
                            .font(.caption)
                            .foregroundStyle(.secondary)
                    }
                }
            }
        }
        .padding()
        .background(Color(.systemBackground))
        .clipShape(RoundedRectangle(cornerRadius: 15))
        .shadow(color: .black.opacity(0.1), radius: 5)
    }
    
    private var recentTransactions: some View {
        VStack(alignment: .leading, spacing: 16) {
            Text("Recent Transactions")
                .font(.title3)
                .fontWeight(.semibold)
            
            ForEach(transactions) { transaction in
                TransactionRow(transaction: transaction)
            }
        }
    }
}

struct MetricCard: View {
    let metric: FinancialMetric
    
    var body: some View {
        VStack(alignment: .leading, spacing: 12) {
            HStack {
                Image(systemName: metric.icon)
                    .foregroundStyle(metric.color)
                Text(metric.title)
                    .foregroundStyle(.secondary)
            }
            .font(.subheadline)
            
            HStack(alignment: .firstTextBaseline, spacing: 8) {
                Text("$\(metric.value, specifier: "%.2f")")
                    .font(.title3)
                    .fontWeight(.bold)
                
                if metric.trend != 0 {
                    HStack(spacing: 2) {
                        Image(systemName: metric.trend > 0 ? "arrow.up.right" : "arrow.down.right")
                        Text("\(abs(metric.trend), specifier: "%.1f")%")
                    }
                    .font(.caption)
                    .foregroundStyle(metric.trend > 0 ? .green : .red)
                }
            }
        }
        .padding()
        .frame(maxWidth: .infinity, alignment: .leading)
        .background(Color(.systemBackground))
        .clipShape(RoundedRectangle(cornerRadius: 15))
        .shadow(color: .black.opacity(0.1), radius: 5)
    }
}

struct TransactionRow: View {
    let transaction: Transaction
    
    var body: some View {
        HStack(spacing: 16) {
            Image(systemName: transaction.category.icon)
                .font(.title2)
                .foregroundStyle(transaction.category.color)
                .frame(width: 44, height: 44)
                .background(transaction.category.color.opacity(0.1))
                .clipShape(Circle())
            
            VStack(alignment: .leading, spacing: 4) {
                Text(transaction.title)
                    .fontWeight(.medium)
                
                Text(transaction.date, style: .date)
                    .font(.caption)
                    .foregroundStyle(.secondary)
            }
            
            Spacer()
            
            Text(transaction.isIncome ? "+$\(transaction.amount, specifier: "%.2f")" : "-$\(transaction.amount, specifier: "%.2f")")
                .fontWeight(.medium)
                .foregroundStyle(transaction.isIncome ? .green : .primary)
        }
        .padding()
        .background(Color(.systemBackground))
        .clipShape(RoundedRectangle(cornerRadius: 15))
        .shadow(color: .black.opacity(0.1), radius: 5)
    }
}

Similar Blogs

View All Articles
How to Translate Xcode String Catalogs with AI

How to Translate Xcode String Catalogs with AI

Learn how to efficiently translate Xcode string catalogs using AI fast, streamlining localization for your iOS and SwiftUI applications.

by dockui
May 4
How to optimize your SwiftUI app in 2026

How to optimize your SwiftUI app in 2026

Discover top strategies to optimize your SwiftUI app in 2026, enhancing performance, responsiveness, and maintainability with modern concurrency.

by dockui
Apr 29
SwiftUI: iOS Confirmation Alert (Confirm + Cancel)

SwiftUI: iOS Confirmation Alert (Confirm + Cancel)

SwiftUI iOS confirmation alert with Confirm and Cancel buttons. Beginners guide to building safe actions, destructive deletes, and commit dialogs.

by dockui
Nov 11
SwiftUI: IOS Haptic Feedback Guide 2026

SwiftUI: IOS Haptic Feedback Guide 2026

Add click to vibrate haptic feedback in SwiftUI. Full guide to UIImpactFeedbackgenerator, success, error, selection, and tap vibration patterns with code.

by dockui
Nov 11

Code copied to clipboard!