104 lines
3.6 KiB
Swift
104 lines
3.6 KiB
Swift
import SwiftUI
|
|
import Observation
|
|
|
|
@Observable
|
|
class MoneyCounterViewModel {
|
|
struct Denomination: Identifiable, Codable, Equatable {
|
|
var id: UUID = UUID()
|
|
let value: Double
|
|
var count: Int = 0
|
|
var isRoll: Bool = false
|
|
}
|
|
|
|
var looseDenominations: [Denomination] = [
|
|
Denomination(value: 0.05),
|
|
Denomination(value: 0.10),
|
|
Denomination(value: 0.25),
|
|
Denomination(value: 1.00),
|
|
Denomination(value: 2.00),
|
|
Denomination(value: 5.00),
|
|
Denomination(value: 10.00),
|
|
Denomination(value: 20.00),
|
|
Denomination(value: 50.00),
|
|
Denomination(value: 100.00)
|
|
]
|
|
|
|
var rollDenominations: [Denomination] = [
|
|
Denomination(value: 2.00, isRoll: true),
|
|
Denomination(value: 5.00, isRoll: true),
|
|
Denomination(value: 10.00, isRoll: true),
|
|
Denomination(value: 25.00, isRoll: true),
|
|
Denomination(value: 50.00, isRoll: true)
|
|
]
|
|
|
|
var startingFloat: Double = 0.0
|
|
|
|
init() {
|
|
loadCache()
|
|
}
|
|
|
|
var total: Double {
|
|
let looseTotal = looseDenominations.reduce(0) { $0 + ($1.value * Double($1.count)) }
|
|
let rollsTotal = rollDenominations.reduce(0) { $0 + ($1.value * Double($1.count)) }
|
|
return looseTotal + rollsTotal
|
|
}
|
|
|
|
var discrepancy: Double {
|
|
total - startingFloat
|
|
}
|
|
|
|
func reset() {
|
|
for i in looseDenominations.indices { looseDenominations[i].count = 0 }
|
|
for i in rollDenominations.indices { rollDenominations[i].count = 0 }
|
|
// The float is intentionally NOT reset here anymore so it persists
|
|
saveCache()
|
|
}
|
|
|
|
func generateSnapshot() -> [CountSnapshot] {
|
|
let loose = looseDenominations.map { CountSnapshot(id: $0.id, value: $0.value, count: $0.count, isRoll: $0.isRoll) }
|
|
let rolls = rollDenominations.map { CountSnapshot(id: $0.id, value: $0.value, count: $0.count, isRoll: $0.isRoll) }
|
|
return loose + rolls
|
|
}
|
|
|
|
func restore(from snapshot: [CountSnapshot], float: Double) {
|
|
startingFloat = float
|
|
|
|
for snap in snapshot {
|
|
if snap.isRoll {
|
|
if let index = rollDenominations.firstIndex(where: { $0.value == snap.value }) {
|
|
rollDenominations[index].count = snap.count
|
|
}
|
|
} else {
|
|
if let index = looseDenominations.firstIndex(where: { $0.value == snap.value }) {
|
|
looseDenominations[index].count = snap.count
|
|
}
|
|
}
|
|
}
|
|
saveCache()
|
|
}
|
|
|
|
// MARK: - Caching Logic
|
|
func saveCache() {
|
|
if let looseData = try? JSONEncoder().encode(looseDenominations) {
|
|
UserDefaults.standard.set(looseData, forKey: "cachedLoose")
|
|
}
|
|
if let rollData = try? JSONEncoder().encode(rollDenominations) {
|
|
UserDefaults.standard.set(rollData, forKey: "cachedRolls")
|
|
}
|
|
UserDefaults.standard.set(startingFloat, forKey: "cachedFloat")
|
|
}
|
|
|
|
private func loadCache() {
|
|
if let looseData = UserDefaults.standard.data(forKey: "cachedLoose"),
|
|
let decodedLoose = try? JSONDecoder().decode([Denomination].self, from: looseData) {
|
|
looseDenominations = decodedLoose
|
|
}
|
|
|
|
if let rollData = UserDefaults.standard.data(forKey: "cachedRolls"),
|
|
let decodedRolls = try? JSONDecoder().decode([Denomination].self, from: rollData) {
|
|
rollDenominations = decodedRolls
|
|
}
|
|
|
|
startingFloat = UserDefaults.standard.double(forKey: "cachedFloat")
|
|
}
|
|
}
|