- Add StockDataSource to fetch quotes from Yahoo Finance API - Add StockSettingsStore for persisting user's stock symbols - Add StockSettingsView with UI to manage symbols (max 5) - Add STOCK feed item type and ranker weight (0.3) - Integrate stock fetch into ContextOrchestrator pipeline - Stock cards appear in FYI bucket and sync to Glass via BLE 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
49 lines
1.4 KiB
Swift
49 lines
1.4 KiB
Swift
//
|
|
// StockSettingsStore.swift
|
|
// iris
|
|
//
|
|
|
|
import Foundation
|
|
import Combine
|
|
|
|
@MainActor
|
|
final class StockSettingsStore: ObservableObject {
|
|
nonisolated static let userDefaultsKey = "iris.stock.symbols"
|
|
|
|
@Published private(set) var symbols: [String] = []
|
|
|
|
private let maxSymbols = 5
|
|
|
|
init() {
|
|
loadSymbols()
|
|
}
|
|
|
|
private func loadSymbols() {
|
|
symbols = UserDefaults.standard.stringArray(forKey: Self.userDefaultsKey) ?? []
|
|
}
|
|
|
|
func saveSymbols(_ newSymbols: [String]) {
|
|
let cleaned = newSymbols
|
|
.map { $0.uppercased().trimmingCharacters(in: .whitespacesAndNewlines) }
|
|
.filter { !$0.isEmpty }
|
|
.prefix(maxSymbols)
|
|
symbols = Array(cleaned)
|
|
UserDefaults.standard.set(symbols, forKey: Self.userDefaultsKey)
|
|
}
|
|
|
|
@discardableResult
|
|
func addSymbol(_ symbol: String) -> Bool {
|
|
guard symbols.count < maxSymbols else { return false }
|
|
let cleaned = symbol.uppercased().trimmingCharacters(in: .whitespacesAndNewlines)
|
|
guard !cleaned.isEmpty, !symbols.contains(cleaned) else { return false }
|
|
symbols.append(cleaned)
|
|
UserDefaults.standard.set(symbols, forKey: Self.userDefaultsKey)
|
|
return true
|
|
}
|
|
|
|
func removeSymbol(_ symbol: String) {
|
|
symbols.removeAll { $0 == symbol.uppercased() }
|
|
UserDefaults.standard.set(symbols, forKey: Self.userDefaultsKey)
|
|
}
|
|
}
|