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>
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
//
|
||||
// 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")
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user