mirror of
https://github.com/VGEAREN/Stockbar.git
synced 2026-10-07 16:47:58 +08:00
Adding Market.krStock cascades into several exhaustive switches that must all update together: ExchangeRates.convert, DisplayCurrency, StockChartView ranges and labels. Bundles tasks 2/3/4/5/14 into one build-passing landing. - Market enum: add krStock case + kr_ prefix routing in Market.from - ExchangeRates: add usdToKrw (fallback 1380), krwToCny derived, KRW path in convert - DisplayCurrency: add .krw (₩), display name 韩元 - CurrencyService.fetchRates: include fx_susdkrw in Sina FX batch URL - StockChartView: KR fullDayRange 0...389 (KST 09:00-15:30, 390 min); KR axis labels 09:00/10:30/12:00/13:30/15:30 Tests: +5 Stock cases for KR, +8 CurrencyKRWTests covering all KR↔CNY/USD/HKD/KRW conversion paths and fallback constant.
98 lines
3.4 KiB
Swift
98 lines
3.4 KiB
Swift
import Foundation
|
|
|
|
enum DisplayCurrency: String, Codable, CaseIterable {
|
|
case cny = "CNY"
|
|
case hkd = "HKD"
|
|
case usd = "USD"
|
|
case krw = "KRW"
|
|
|
|
var symbol: String {
|
|
switch self {
|
|
case .cny: return "¥"
|
|
case .hkd: return "HK$"
|
|
case .usd: return "$"
|
|
case .krw: return "₩"
|
|
}
|
|
}
|
|
|
|
var displayName: String {
|
|
switch self {
|
|
case .cny: return "人民币 ¥"
|
|
case .hkd: return "港币 HK$"
|
|
case .usd: return "美元 $"
|
|
case .krw: return "韩元 ₩"
|
|
}
|
|
}
|
|
}
|
|
|
|
enum SortRule: String, Codable, CaseIterable {
|
|
case changeDesc = "changeDesc"
|
|
case changeAsc = "changeAsc"
|
|
|
|
var displayName: String {
|
|
switch self {
|
|
case .changeDesc: return "涨跌幅降序"
|
|
case .changeAsc: return "涨跌幅升序"
|
|
}
|
|
}
|
|
}
|
|
|
|
enum USPriceMode: String, Codable, CaseIterable {
|
|
case sessionPrice = "session"
|
|
case regularPrice = "regular"
|
|
|
|
var displayName: String {
|
|
switch self {
|
|
case .sessionPrice: return "当前价(时段价格)"
|
|
case .regularPrice: return "盘中价"
|
|
}
|
|
}
|
|
}
|
|
|
|
enum ColorTheme: String, Codable, CaseIterable {
|
|
case chinese = "chinese" // 红涨绿跌
|
|
case western = "western" // 绿涨红跌
|
|
|
|
var displayName: String {
|
|
switch self {
|
|
case .chinese: return "红涨绿跌"
|
|
case .western: return "绿涨红跌"
|
|
}
|
|
}
|
|
}
|
|
|
|
struct AppSettings {
|
|
var statusBarStockId: String = ""
|
|
var refreshInterval: Int = 5
|
|
var colorScheme: ColorTheme = .chinese
|
|
var displayCurrency: DisplayCurrency = .cny
|
|
var sortRule: SortRule = .changeDesc
|
|
var usPriceMode: USPriceMode = .sessionPrice
|
|
var groupHoldings: Bool = false
|
|
var activeWatchlistId: String? = nil // nil = 真实持仓
|
|
|
|
static let validRefreshIntervals = [3, 5, 10, 30]
|
|
|
|
var upColorName: String { colorScheme == .chinese ? "upRed" : "upGreen" }
|
|
var downColorName: String { colorScheme == .chinese ? "downGreen" : "downRed" }
|
|
}
|
|
|
|
// MARK: - Codable(容错:缺失字段使用默认值)
|
|
extension AppSettings: Codable {
|
|
enum CodingKeys: String, CodingKey {
|
|
case statusBarStockId, refreshInterval, colorScheme, displayCurrency, sortRule, usPriceMode, groupHoldings, activeWatchlistId
|
|
}
|
|
|
|
init(from decoder: Decoder) throws {
|
|
let c = try decoder.container(keyedBy: CodingKeys.self)
|
|
statusBarStockId = (try? c.decodeIfPresent(String.self, forKey: .statusBarStockId)) ?? ""
|
|
refreshInterval = (try? c.decodeIfPresent(Int.self, forKey: .refreshInterval)) ?? 5
|
|
colorScheme = (try? c.decodeIfPresent(ColorTheme.self, forKey: .colorScheme)) ?? .chinese
|
|
displayCurrency = (try? c.decodeIfPresent(DisplayCurrency.self, forKey: .displayCurrency)) ?? .cny
|
|
sortRule = (try? c.decodeIfPresent(SortRule.self, forKey: .sortRule)) ?? .changeDesc
|
|
usPriceMode = (try? c.decodeIfPresent(USPriceMode.self, forKey: .usPriceMode)) ?? .sessionPrice
|
|
groupHoldings = (try? c.decodeIfPresent(Bool.self, forKey: .groupHoldings)) ?? false
|
|
activeWatchlistId = try? c.decodeIfPresent(String.self, forKey: .activeWatchlistId)
|
|
}
|
|
}
|