// // TripCardGenerator.swift // SportsTime // // Generates shareable trip summary cards with route map. // import SwiftUI import UIKit // MARK: - Trip Share Content struct TripShareContent: ShareableContent { let trip: Trip var cardType: ShareCardType { .tripSummary } @MainActor func render(theme: ShareTheme) async throws -> UIImage { let mapGenerator = ShareMapSnapshotGenerator() let mapSnapshot = await mapGenerator.generateRouteMap( stops: trip.stops, theme: theme ) let cardView = TripCardView( trip: trip, theme: theme, mapSnapshot: mapSnapshot ) let renderer = ImageRenderer(content: cardView) renderer.scale = 3.0 guard let image = renderer.uiImage else { throw ShareError.renderingFailed } return image } } // MARK: - Trip Card View private struct TripCardView: View { let trip: Trip let theme: ShareTheme let mapSnapshot: UIImage? private var sportTitle: String { if trip.uniqueSports.count == 1, let sport = trip.uniqueSports.first { return "My \(sport.displayName) Road Trip" } return "My Sports Road Trip" } private var primarySport: Sport? { trip.uniqueSports.first } var body: some View { ZStack { ShareCardBackground(theme: theme) VStack(spacing: 40) { ShareCardHeader( title: sportTitle, sport: primarySport, theme: theme ) // Map if let snapshot = mapSnapshot { Image(uiImage: snapshot) .resizable() .aspectRatio(contentMode: .fit) .frame(maxWidth: 960, maxHeight: 600) .clipShape(RoundedRectangle(cornerRadius: 20)) .overlay { RoundedRectangle(cornerRadius: 20) .stroke(theme.accentColor.opacity(0.3), lineWidth: 2) } } // Date range Text(trip.formattedDateRange) .font(.system(size: 32, weight: .medium)) .foregroundStyle(theme.textColor) // Stats row ShareStatsRow( stats: [ (value: String(format: "%.0f", trip.totalDistanceMiles), label: "miles"), (value: "\(trip.totalGames)", label: "games"), (value: "\(trip.cities.count)", label: "cities") ], theme: theme ) // City trail cityTrail Spacer() ShareCardFooter(theme: theme) } .padding(ShareCardDimensions.padding) } .frame( width: ShareCardDimensions.cardSize.width, height: ShareCardDimensions.cardSize.height ) } private var cityTrail: some View { let cities = trip.cities let displayText = cities.joined(separator: " → ") return Text(displayText) .font(.system(size: 24, weight: .medium)) .foregroundStyle(theme.secondaryTextColor) .multilineTextAlignment(.center) .lineLimit(3) .padding(.horizontal, 40) } }