Files
iceglass/Shared/Models/GameState.swift
T
rzen 541aa3d52c Show full playoff bracket, mark series results, harden API decoding
Playoffs:
- List every round played so far (Round 1 → current) instead of only the
  current round, on both macOS menu and iPhone
- Strike through the eliminated team's tricode in a finished series and drop
  the now-redundant "(Final … wins)" tag on completed earlier rounds
- Refetch the bracket when a finished game implies more completed games than
  the cached bracket records, so the series score and round no longer get
  stuck on stale data after cold launch or the NHL bracket endpoint's lag

API robustness:
- Tolerate optional gameCenterLink/startTimeUTC on TBD playoff matchups so the
  scoreboard decode no longer aborts
- Reject API state regressions via a monotonic FUT→…→OFF progression rank so a
  brief glitch can't downgrade a finished game back to "-:-"
2026-05-30 08:21:28 -04:00

81 lines
2.3 KiB
Swift

//
// GameState.swift
// IceGlass
//
// Copyright 2026 Rouslan Zenetl. All Rights Reserved.
//
import Foundation
enum GameState: String, Codable {
case future = "FUT" // More than 30 minutes prior to game start
case pre = "PRE" // Pre-game, <30 minutes until puck drops
case live = "LIVE" // Game has started
case crit = "CRIT" // Last 5 minutes of regulation, OT or SO
case over = "OVER" // Soft final
case final_ = "FINAL" // Hard final
case official = "OFF" // Official
var isLive: Bool {
self == .live || self == .crit
}
var isOver: Bool {
self == .over || self == .final_ || self == .official
}
var isFuture: Bool {
self == .future || self == .pre
}
/// Short tag for display in menu rows. Empty for future games the start
/// time already implies that state.
var shortTag: String {
switch self {
case .future: return ""
case .pre: return "PRE"
case .live: return "LIVE"
case .crit: return "CRIT"
case .over: return "OVER"
case .final_: return "FINAL"
case .official: return "OFF"
}
}
/// Monotonic ordering along the FUTPRELIVECRITOVERFINALOFF progression.
/// Used to detect and reject API regressions that briefly downgrade a
/// finished game back to FUT during the daily focusedDate rollover.
var progressionRank: Int {
switch self {
case .future: return 0
case .pre: return 1
case .live: return 2
case .crit: return 3
case .over: return 4
case .final_: return 5
case .official: return 6
}
}
/// Same ranking, addressable by the raw API string. Unknown states get -1
/// so any known state replaces them.
static func progressionRank(of rawState: String) -> Int {
GameState(rawValue: rawState)?.progressionRank ?? -1
}
var pollingInterval: PollingInterval {
switch self {
case .future:
return .gameDay
case .pre:
return .preGame
case .live, .crit:
return .liveGame
case .over, .final_:
return .everyMinute
case .official:
return .idle
}
}
}