Files
Michael Simard 1ade3b39ff Initial implementation of Fantasy Hockey watchOS app
Implemented complete TCA architecture for iOS and watchOS targets:
- Authentication flow (Sign in with Apple + Yahoo OAuth)
- OAuth token management with iCloud Key-Value Storage
- Yahoo Fantasy Sports API client with async/await
- Watch Connectivity for iPhone ↔ Watch data sync
- Complete UI for both iPhone and Watch platforms

Core features:
- Matchup score display
- Category breakdown with win/loss/tie indicators
- Roster status tracking
- Manual refresh functionality
- Persistent data caching on Watch

Technical stack:
- The Composable Architecture for state management
- Swift Concurrency (async/await, actors)
- WatchConnectivity framework
- Sign in with Apple
- OAuth 2.0 authentication flow

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-07 00:40:31 -06:00

85 lines
2.6 KiB
Swift

//
// CategoryBreakdownView.swift
// FantasyWatch Watch App
//
// Created by Claude Code
//
import SwiftUI
struct CategoryBreakdownView: View {
let categories: [CategoryScore]
var body: some View {
List(categories) { category in
HStack(spacing: 8) {
Text(category.name)
.font(.caption)
.fontWeight(.semibold)
.frame(width: 40, alignment: .leading)
Spacer()
VStack(alignment: .trailing, spacing: 2) {
Text(category.userValue)
.font(.caption)
.fontWeight(.semibold)
.foregroundColor(colorForComparison(category.comparison))
Text(category.opponentValue)
.font(.caption2)
.foregroundColor(.secondary)
}
comparisonIcon(category.comparison)
.font(.caption2)
.frame(width: 20)
}
}
.navigationTitle("Categories")
.navigationBarTitleDisplayMode(.inline)
}
private func colorForComparison(_ comparison: CategoryScore.ComparisonResult) -> Color {
switch comparison {
case .winning:
return .green
case .losing:
return .red
case .tied:
return .orange
}
}
@ViewBuilder
private func comparisonIcon(_ comparison: CategoryScore.ComparisonResult) -> some View {
switch comparison {
case .winning:
Image(systemName: "arrow.up")
.foregroundColor(.green)
case .losing:
Image(systemName: "arrow.down")
.foregroundColor(.red)
case .tied:
Image(systemName: "equal")
.foregroundColor(.orange)
}
}
}
#Preview {
NavigationStack {
CategoryBreakdownView(
categories: [
CategoryScore(statID: "1", name: "G", userValue: "10", opponentValue: "8"),
CategoryScore(statID: "2", name: "A", userValue: "15", opponentValue: "18"),
CategoryScore(statID: "3", name: "PPP", userValue: "5", opponentValue: "5"),
CategoryScore(statID: "4", name: "SOG", userValue: "200", opponentValue: "195"),
CategoryScore(statID: "5", name: "W", userValue: "3", opponentValue: "4"),
CategoryScore(statID: "6", name: "GAA", userValue: "2.45", opponentValue: "2.80"),
CategoryScore(statID: "7", name: "SV%", userValue: "0.915", opponentValue: "0.905")
]
)
}
}