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 "-:-"
This commit is contained in:
@@ -106,7 +106,8 @@ struct GameRow: View {
|
||||
}
|
||||
|
||||
private func open() {
|
||||
guard let url = URL(string: game.gameCenterUrl) else { return }
|
||||
guard let urlString = game.gameCenterUrl,
|
||||
let url = URL(string: urlString) else { return }
|
||||
UIApplication.shared.open(url)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,17 +21,21 @@ struct MainView: View {
|
||||
)
|
||||
.padding(.horizontal)
|
||||
|
||||
if !viewModel.currentRoundSeriesItems.isEmpty,
|
||||
let round = viewModel.currentRoundNumber {
|
||||
PlayoffRoundSection(
|
||||
round: round,
|
||||
items: viewModel.currentRoundSeriesItems
|
||||
)
|
||||
.padding(.horizontal)
|
||||
let roundGroups = viewModel.roundSeriesGroups
|
||||
let latestRound = roundGroups.last?.round
|
||||
ForEach(roundGroups, id: \.round) { group in
|
||||
if !group.items.isEmpty {
|
||||
PlayoffRoundSection(
|
||||
round: group.round,
|
||||
items: group.items,
|
||||
showStatus: group.round == latestRound
|
||||
)
|
||||
.padding(.horizontal)
|
||||
}
|
||||
}
|
||||
|
||||
let gameDays = viewModel.gamesByDate
|
||||
if gameDays.isEmpty && viewModel.currentRoundSeriesItems.isEmpty {
|
||||
if gameDays.isEmpty && roundGroups.isEmpty {
|
||||
emptyState
|
||||
.padding(.horizontal)
|
||||
.padding(.top, 40)
|
||||
|
||||
@@ -10,6 +10,7 @@ import SwiftUI
|
||||
struct PlayoffRoundSection: View {
|
||||
let round: Int
|
||||
let items: [MainService.RoundSeriesItem]
|
||||
var showStatus: Bool = true
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
@@ -20,7 +21,7 @@ struct PlayoffRoundSection: View {
|
||||
|
||||
VStack(spacing: 0) {
|
||||
ForEach(items, id: \.series.seriesLetter) { item in
|
||||
SeriesRow(item: item)
|
||||
SeriesRow(item: item, showStatus: showStatus)
|
||||
if item.series.seriesLetter != items.last?.series.seriesLetter {
|
||||
Divider()
|
||||
}
|
||||
|
||||
@@ -9,6 +9,9 @@ import SwiftUI
|
||||
|
||||
struct SeriesRow: View {
|
||||
let item: MainService.RoundSeriesItem
|
||||
/// Completed earlier rounds hide the status/next-game column; the struck-out
|
||||
/// loser already conveys the result.
|
||||
var showStatus: Bool = true
|
||||
|
||||
private static let logoSize: CGFloat = 40
|
||||
|
||||
@@ -17,7 +20,9 @@ struct SeriesRow: View {
|
||||
HStack(alignment: .center, spacing: 10) {
|
||||
matchupBlock
|
||||
Spacer(minLength: 8)
|
||||
rightContent
|
||||
if showStatus {
|
||||
rightContent
|
||||
}
|
||||
}
|
||||
.padding(.horizontal, 14)
|
||||
.padding(.vertical, 8)
|
||||
@@ -34,6 +39,7 @@ struct SeriesRow: View {
|
||||
Text(bottom)
|
||||
.font(.title3.monospaced())
|
||||
.fontWeight(.semibold)
|
||||
.strikethrough(item.series.loser == bottom)
|
||||
.foregroundStyle(.primary)
|
||||
.lineLimit(1)
|
||||
.fixedSize()
|
||||
@@ -47,6 +53,7 @@ struct SeriesRow: View {
|
||||
Text(top)
|
||||
.font(.title3.monospaced())
|
||||
.fontWeight(.semibold)
|
||||
.strikethrough(item.series.loser == top)
|
||||
.foregroundStyle(.primary)
|
||||
.lineLimit(1)
|
||||
.fixedSize()
|
||||
|
||||
Reference in New Issue
Block a user