Files
iceglass/IceGlass-iOS/Views/GameRow.swift
T
rzen f6785321f4 Enlarge logos, tricodes, and inline scores on iPhone rows
Game and series rows now lead with a 40pt logo + title3-monospaced
tricode + bold inline score + tricode + logo, so the matchup fills
the row's vertical space and reads at a glance. For future games the
score is replaced by an "@" separator. Right-side metadata (game number,
status, kickoff time) stays at subheadline/caption2 so it's secondary.

Tricodes and scores get .lineLimit(1).fixedSize() to keep everything
on one line on tighter widths.
2026-04-25 15:19:14 -04:00

119 lines
3.5 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//
// GameRow.swift
// IceGlass-iOS
//
// Copyright 2026 Rouslan Zenetl. All Rights Reserved.
//
import SwiftUI
struct GameRow: View {
let game: Scoreboard.Game
private static let logoSize: CGFloat = 40
var body: some View {
Button(action: open) {
HStack(spacing: 10) {
if game.gameType == 2 {
Text("#\(game.seasonGameNumber)")
.font(.caption2.monospacedDigit())
.foregroundStyle(.tertiary)
.frame(width: 44, alignment: .leading)
}
matchupBlock
Spacer(minLength: 8)
rightContent
}
.padding(.horizontal, 14)
.padding(.vertical, 8)
.contentShape(Rectangle())
}
.buttonStyle(.plain)
}
private var matchupBlock: some View {
let state = game.parsedGameState
let showScore = !state.isFuture
return HStack(spacing: 6) {
TeamLogo(abbrev: game.awayTeam.abbrev, size: Self.logoSize)
Text(game.awayTeam.abbrev)
.font(.title3.monospaced())
.fontWeight(.semibold)
.foregroundStyle(.primary)
.lineLimit(1)
.fixedSize()
if showScore {
Text(scoreText)
.font(.title3.monospacedDigit())
.fontWeight(.bold)
.foregroundStyle(.primary)
.lineLimit(1)
.fixedSize()
.padding(.horizontal, 2)
} else {
Text("@")
.font(.title3)
.foregroundStyle(.tertiary)
}
Text(game.homeTeam.abbrev)
.font(.title3.monospaced())
.fontWeight(.semibold)
.foregroundStyle(.primary)
.lineLimit(1)
.fixedSize()
TeamLogo(abbrev: game.homeTeam.abbrev, size: Self.logoSize)
}
}
@ViewBuilder
private var rightContent: some View {
let state = game.parsedGameState
VStack(alignment: .trailing, spacing: 2) {
Text(primaryRightLine)
.font(.subheadline.monospacedDigit())
.foregroundStyle(state.isLive ? .red : .secondary)
if let secondary = secondaryRightLine {
Text(secondary)
.font(.caption2)
.foregroundStyle(.tertiary)
}
}
}
private var primaryRightLine: String {
let state = game.parsedGameState
if state.isFuture {
return game.startTimeET.trimmingCharacters(in: .whitespaces)
}
let tag = state.shortTag
return tag.isEmpty
? game.startTimeET.trimmingCharacters(in: .whitespaces)
: tag
}
private var secondaryRightLine: String? {
let state = game.parsedGameState
guard !state.isFuture, !state.shortTag.isEmpty else { return nil }
// For finished games, show kickoff time below FINAL/OFF; for live games, just show tag.
if state.isLive { return nil }
return game.startTimeET.trimmingCharacters(in: .whitespaces)
}
private var scoreText: String {
let a = game.awayTeam.score ?? 0
let h = game.homeTeam.score ?? 0
return "\(a)\(h)"
}
private func open() {
guard let url = URL(string: game.gameCenterUrl) else { return }
UIApplication.shared.open(url)
}
}