Initial commit: SportsTime trip planning app
- Three-scenario planning engine (A: date range, B: selected games, C: directional routes) - GeographicRouteExplorer with anchor game support for route exploration - Shared ItineraryBuilder for travel segment calculation - TravelEstimator for driving time/distance estimation - SwiftUI views for trip creation and detail display - CloudKit integration for schedule data - Python scraping scripts for sports schedules 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
193
SportsTime/Core/Models/CloudKit/CKModels.swift
Normal file
193
SportsTime/Core/Models/CloudKit/CKModels.swift
Normal file
@@ -0,0 +1,193 @@
|
||||
//
|
||||
// CKModels.swift
|
||||
// SportsTime
|
||||
//
|
||||
// CloudKit Record Type Definitions for Public Database
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CloudKit
|
||||
|
||||
// MARK: - Record Type Constants
|
||||
|
||||
enum CKRecordType {
|
||||
static let team = "Team"
|
||||
static let stadium = "Stadium"
|
||||
static let game = "Game"
|
||||
static let sport = "Sport"
|
||||
}
|
||||
|
||||
// MARK: - CKTeam
|
||||
|
||||
struct CKTeam {
|
||||
static let idKey = "teamId"
|
||||
static let nameKey = "name"
|
||||
static let abbreviationKey = "abbreviation"
|
||||
static let sportKey = "sport"
|
||||
static let cityKey = "city"
|
||||
static let stadiumRefKey = "stadiumRef"
|
||||
static let logoURLKey = "logoURL"
|
||||
static let primaryColorKey = "primaryColor"
|
||||
static let secondaryColorKey = "secondaryColor"
|
||||
|
||||
let record: CKRecord
|
||||
|
||||
init(record: CKRecord) {
|
||||
self.record = record
|
||||
}
|
||||
|
||||
init(team: Team, stadiumRecordID: CKRecord.ID) {
|
||||
let record = CKRecord(recordType: CKRecordType.team)
|
||||
record[CKTeam.idKey] = team.id.uuidString
|
||||
record[CKTeam.nameKey] = team.name
|
||||
record[CKTeam.abbreviationKey] = team.abbreviation
|
||||
record[CKTeam.sportKey] = team.sport.rawValue
|
||||
record[CKTeam.cityKey] = team.city
|
||||
record[CKTeam.stadiumRefKey] = CKRecord.Reference(recordID: stadiumRecordID, action: .none)
|
||||
record[CKTeam.logoURLKey] = team.logoURL?.absoluteString
|
||||
record[CKTeam.primaryColorKey] = team.primaryColor
|
||||
record[CKTeam.secondaryColorKey] = team.secondaryColor
|
||||
self.record = record
|
||||
}
|
||||
|
||||
var team: Team? {
|
||||
guard let idString = record[CKTeam.idKey] as? String,
|
||||
let id = UUID(uuidString: idString),
|
||||
let name = record[CKTeam.nameKey] as? String,
|
||||
let abbreviation = record[CKTeam.abbreviationKey] as? String,
|
||||
let sportRaw = record[CKTeam.sportKey] as? String,
|
||||
let sport = Sport(rawValue: sportRaw),
|
||||
let city = record[CKTeam.cityKey] as? String,
|
||||
let stadiumRef = record[CKTeam.stadiumRefKey] as? CKRecord.Reference,
|
||||
let stadiumIdString = stadiumRef.recordID.recordName.split(separator: ":").last,
|
||||
let stadiumId = UUID(uuidString: String(stadiumIdString))
|
||||
else { return nil }
|
||||
|
||||
let logoURL = (record[CKTeam.logoURLKey] as? String).flatMap { URL(string: $0) }
|
||||
|
||||
return Team(
|
||||
id: id,
|
||||
name: name,
|
||||
abbreviation: abbreviation,
|
||||
sport: sport,
|
||||
city: city,
|
||||
stadiumId: stadiumId,
|
||||
logoURL: logoURL,
|
||||
primaryColor: record[CKTeam.primaryColorKey] as? String,
|
||||
secondaryColor: record[CKTeam.secondaryColorKey] as? String
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - CKStadium
|
||||
|
||||
struct CKStadium {
|
||||
static let idKey = "stadiumId"
|
||||
static let nameKey = "name"
|
||||
static let cityKey = "city"
|
||||
static let stateKey = "state"
|
||||
static let locationKey = "location"
|
||||
static let capacityKey = "capacity"
|
||||
static let yearOpenedKey = "yearOpened"
|
||||
static let imageURLKey = "imageURL"
|
||||
|
||||
let record: CKRecord
|
||||
|
||||
init(record: CKRecord) {
|
||||
self.record = record
|
||||
}
|
||||
|
||||
init(stadium: Stadium) {
|
||||
let record = CKRecord(recordType: CKRecordType.stadium)
|
||||
record[CKStadium.idKey] = stadium.id.uuidString
|
||||
record[CKStadium.nameKey] = stadium.name
|
||||
record[CKStadium.cityKey] = stadium.city
|
||||
record[CKStadium.stateKey] = stadium.state
|
||||
record[CKStadium.locationKey] = CLLocation(latitude: stadium.latitude, longitude: stadium.longitude)
|
||||
record[CKStadium.capacityKey] = stadium.capacity
|
||||
record[CKStadium.yearOpenedKey] = stadium.yearOpened
|
||||
record[CKStadium.imageURLKey] = stadium.imageURL?.absoluteString
|
||||
self.record = record
|
||||
}
|
||||
|
||||
var stadium: Stadium? {
|
||||
guard let idString = record[CKStadium.idKey] as? String,
|
||||
let id = UUID(uuidString: idString),
|
||||
let name = record[CKStadium.nameKey] as? String,
|
||||
let city = record[CKStadium.cityKey] as? String,
|
||||
let state = record[CKStadium.stateKey] as? String,
|
||||
let location = record[CKStadium.locationKey] as? CLLocation,
|
||||
let capacity = record[CKStadium.capacityKey] as? Int
|
||||
else { return nil }
|
||||
|
||||
let imageURL = (record[CKStadium.imageURLKey] as? String).flatMap { URL(string: $0) }
|
||||
|
||||
return Stadium(
|
||||
id: id,
|
||||
name: name,
|
||||
city: city,
|
||||
state: state,
|
||||
latitude: location.coordinate.latitude,
|
||||
longitude: location.coordinate.longitude,
|
||||
capacity: capacity,
|
||||
yearOpened: record[CKStadium.yearOpenedKey] as? Int,
|
||||
imageURL: imageURL
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - CKGame
|
||||
|
||||
struct CKGame {
|
||||
static let idKey = "gameId"
|
||||
static let homeTeamRefKey = "homeTeamRef"
|
||||
static let awayTeamRefKey = "awayTeamRef"
|
||||
static let stadiumRefKey = "stadiumRef"
|
||||
static let dateTimeKey = "dateTime"
|
||||
static let sportKey = "sport"
|
||||
static let seasonKey = "season"
|
||||
static let isPlayoffKey = "isPlayoff"
|
||||
static let broadcastInfoKey = "broadcastInfo"
|
||||
|
||||
let record: CKRecord
|
||||
|
||||
init(record: CKRecord) {
|
||||
self.record = record
|
||||
}
|
||||
|
||||
init(game: Game, homeTeamRecordID: CKRecord.ID, awayTeamRecordID: CKRecord.ID, stadiumRecordID: CKRecord.ID) {
|
||||
let record = CKRecord(recordType: CKRecordType.game)
|
||||
record[CKGame.idKey] = game.id.uuidString
|
||||
record[CKGame.homeTeamRefKey] = CKRecord.Reference(recordID: homeTeamRecordID, action: .none)
|
||||
record[CKGame.awayTeamRefKey] = CKRecord.Reference(recordID: awayTeamRecordID, action: .none)
|
||||
record[CKGame.stadiumRefKey] = CKRecord.Reference(recordID: stadiumRecordID, action: .none)
|
||||
record[CKGame.dateTimeKey] = game.dateTime
|
||||
record[CKGame.sportKey] = game.sport.rawValue
|
||||
record[CKGame.seasonKey] = game.season
|
||||
record[CKGame.isPlayoffKey] = game.isPlayoff ? 1 : 0
|
||||
record[CKGame.broadcastInfoKey] = game.broadcastInfo
|
||||
self.record = record
|
||||
}
|
||||
|
||||
func game(homeTeamId: UUID, awayTeamId: UUID, stadiumId: UUID) -> Game? {
|
||||
guard let idString = record[CKGame.idKey] as? String,
|
||||
let id = UUID(uuidString: idString),
|
||||
let dateTime = record[CKGame.dateTimeKey] as? Date,
|
||||
let sportRaw = record[CKGame.sportKey] as? String,
|
||||
let sport = Sport(rawValue: sportRaw),
|
||||
let season = record[CKGame.seasonKey] as? String
|
||||
else { return nil }
|
||||
|
||||
return Game(
|
||||
id: id,
|
||||
homeTeamId: homeTeamId,
|
||||
awayTeamId: awayTeamId,
|
||||
stadiumId: stadiumId,
|
||||
dateTime: dateTime,
|
||||
sport: sport,
|
||||
season: season,
|
||||
isPlayoff: (record[CKGame.isPlayoffKey] as? Int) == 1,
|
||||
broadcastInfo: record[CKGame.broadcastInfoKey] as? String
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user