InvestmentTrackerApp/PortfolioJournal/Repositories/AccountRepository.swift

154 lines
4.4 KiB
Swift

import Foundation
import CoreData
import Combine
class AccountRepository: ObservableObject {
private let context: NSManagedObjectContext
@Published private(set) var accounts: [Account] = []
init(context: NSManagedObjectContext = CoreDataStack.shared.viewContext) {
self.context = context
fetchAccounts()
setupNotificationObserver()
}
private func setupNotificationObserver() {
NotificationCenter.default.addObserver(
self,
selector: #selector(contextDidChange),
name: .NSManagedObjectContextObjectsDidChange,
object: context
)
}
@objc private func contextDidChange(_ notification: Notification) {
fetchAccounts()
}
// MARK: - Fetch
func fetchAccounts() {
context.perform { [weak self] in
guard let self else { return }
let request: NSFetchRequest<Account> = Account.fetchRequest()
request.sortDescriptors = [
NSSortDescriptor(keyPath: \Account.sortOrder, ascending: true),
NSSortDescriptor(keyPath: \Account.createdAt, ascending: true)
]
do {
let fetched = try self.context.fetch(request)
DispatchQueue.main.async {
self.accounts = fetched
}
} catch {
print("Failed to fetch accounts: \(error)")
DispatchQueue.main.async {
self.accounts = []
}
}
}
}
func fetchAccount(by id: UUID) -> Account? {
let request: NSFetchRequest<Account> = Account.fetchRequest()
request.predicate = NSPredicate(format: "id == %@", id as CVarArg)
request.fetchLimit = 1
return try? context.fetch(request).first
}
// MARK: - Create
@discardableResult
func createAccount(
name: String,
currency: String?,
inputMode: InputMode,
notificationFrequency: NotificationFrequency,
customFrequencyMonths: Int = 1
) -> Account {
let account = Account(context: context)
account.name = name
account.currency = currency
account.inputMode = inputMode.rawValue
account.notificationFrequency = notificationFrequency.rawValue
account.customFrequencyMonths = Int16(customFrequencyMonths)
account.sortOrder = Int16(accounts.count)
save()
return account
}
func createDefaultAccountIfNeeded() -> Account {
if let existing = accounts.first {
return existing
}
let defaultCurrency = AppSettings.getOrCreate(in: context).currency
let account = createAccount(
name: "Personal",
currency: defaultCurrency,
inputMode: .simple,
notificationFrequency: .monthly
)
// Attach existing sources to the default account
let request: NSFetchRequest<InvestmentSource> = InvestmentSource.fetchRequest()
if let sources = try? context.fetch(request) {
for source in sources where source.account == nil {
source.account = account
}
save()
}
return account
}
// MARK: - Update
func updateAccount(
_ account: Account,
name: String? = nil,
currency: String? = nil,
inputMode: InputMode? = nil,
notificationFrequency: NotificationFrequency? = nil,
customFrequencyMonths: Int? = nil
) {
if let name = name {
account.name = name
}
if let currency = currency {
account.currency = currency
}
if let inputMode = inputMode {
account.inputMode = inputMode.rawValue
}
if let notificationFrequency = notificationFrequency {
account.notificationFrequency = notificationFrequency.rawValue
}
if let customMonths = customFrequencyMonths {
account.customFrequencyMonths = Int16(customMonths)
}
save()
}
// MARK: - Delete
func deleteAccount(_ account: Account) {
context.delete(account)
save()
}
// MARK: - Save
private func save() {
guard context.hasChanges else { return }
do {
try context.save()
fetchAccounts()
} catch {
print("Failed to save accounts: \(error)")
}
}
}