# Sharing System Overhaul

*Design finalized: January 13, 2026*

## Overview

Complete overhaul of the sharing system to support shareable cards for trip summaries, achievements, and stadium progress. Primary target is Instagram Stories (1080×1920 vertical cards) with user-customizable color themes.

## Goals

- Share trip summaries as visual cards (not just deep links)
- Share achievements (single, collection, milestone, contextual)
- Share stadium progress with map visualization
- User-customizable color themes (8 presets)
- Contextual share buttons throughout the app (low friction)
- Instagram Stories as primary destination

## Architecture

### Protocol-Based Design

All shareable content types conform to a common protocol:

```swift
protocol ShareableContent {
    var cardType: ShareCardType { get }
    func render(theme: ShareTheme) async throws -> UIImage
}

enum ShareCardType {
    case tripSummary
    case achievementSpotlight
    case achievementCollection
    case achievementMilestone
    case achievementContext
    case stadiumProgress
}
```

### Component Hierarchy

```
ShareableContent (protocol)
├── TripShareContent      → TripCardGenerator
├── AchievementShareContent → AchievementCardGenerator
├── ProgressShareContent  → ProgressCardGenerator
└── CollectionShareContent → CollectionCardGenerator
```

### Unified Components

- `ShareTheme` - Color preset definitions
- `ShareCardFooter` - Reusable SportsTime branding footer
- `ShareCardHeader` - Sport icon + title treatment
- `ShareService` - Instagram URL scheme, image export, fallback share sheet

## Theme System

### 8 Color Presets

| Theme | Background Gradient | Accent | Text | Use Case |
|-------|---------------------|--------|------|----------|
| **Dark** | #1A1A2E → #16213E | #FF6B35 | White | Default, premium feel |
| **Light** | #FFFFFF → #F5F5F5 | #FF6B35 | #1A1A2E | Clean, minimal |
| **Midnight** | #0D1B2A → #1B263B | #00D4FF | White | Night game energy |
| **Forest** | #1B4332 → #2D6A4F | #95D5B2 | White | Baseball/outdoor |
| **Sunset** | #FF6B35 → #F7931E | #FFFFFF | White | Bold, attention-grabbing |
| **Berry** | #4A0E4E → #81267E | #FF85A1 | White | Unique, stands out |
| **Ocean** | #023E8A → #0077B6 | #90E0EF | White | Cool, professional |
| **Slate** | #2B2D42 → #3D405B | #F4A261 | #EDF2F4 | Sophisticated neutral |

### Theme Definition

```swift
struct ShareTheme: Identifiable, Hashable {
    let id: String
    let name: String
    let gradientColors: [Color]
    let accentColor: Color
    let textColor: Color
    let secondaryTextColor: Color
    let mapStyle: MapStyle // .light or .dark

    static let all: [ShareTheme] = [.dark, .light, .midnight, .forest, .sunset, .berry, .ocean, .slate]
}
```

Theme preference is persisted per content type via UserDefaults.

## Card Designs

### Card Dimensions

All cards use Instagram Story dimensions: **1080 × 1920 pixels** (9:16 aspect ratio).

### Trip Summary Card

```
┌─────────────────────────────────┐
│  [Sport Icon]                   │  ← Header: 120px
│  "My Baseball Road Trip"        │
├─────────────────────────────────┤
│                                 │
│    ┌─────────────────────┐      │
│    │                     │      │
│    │   MAP SNAPSHOT      │      │  ← Hero map: 600px
│    │   with route line   │      │     Route drawn in accent color
│    │   + city markers    │      │     Visited cities = filled dots
│    │                     │      │
│    └─────────────────────┘      │
│                                 │
├─────────────────────────────────┤
│  "Jun 15 - Jun 22, 2026"        │  ← Date range
├─────────────────────────────────┤
│                                 │
│  ┌───────┐ ┌───────┐ ┌───────┐  │
│  │ 1,847 │ │   5   │ │   4   │  │  ← Stats row
│  │ miles │ │ games │ │cities │  │
│  └───────┘ └───────┘ └───────┘  │
│                                 │
├─────────────────────────────────┤
│  Chicago → Milwaukee → Detroit  │  ← City trail
│  → Cleveland → Pittsburgh       │
├─────────────────────────────────┤
│  [SportsTime logo]              │  ← Footer: 100px
│  "Plan your stadium adventure"  │
└─────────────────────────────────┘
```

**Map Features:**
- Route line drawn using MKPolyline in accent color
- City markers: filled circles with abbreviation labels
- Map style matches theme (muted standard for dark themes)

### Achievement Cards

#### Type 1: Single Spotlight

```
┌─────────────────────────────────┐
│                                 │
│         ┌───────────┐           │
│         │           │           │
│         │  BADGE    │           │  ← Large badge: 400×400px
│         │  GRAPHIC  │           │
│         │           │           │
│         └───────────┘           │
│                                 │
│      "ALL NL WEST"              │  ← Achievement name
│                                 │
│   "Visited all 5 stadiums       │  ← Description
│    in the National League       │
│    West division"               │
│                                 │
│      ✓ Unlocked Jan 12, 2026    │  ← Unlock date
│                                 │
│  [SportsTime logo + tagline]    │
└─────────────────────────────────┘
```

#### Type 2: Collection Grid

```
┌─────────────────────────────────┐
│  "My 2026 Achievements"         │  ← Header with year
├─────────────────────────────────┤
│  ┌─────┐ ┌─────┐ ┌─────┐        │
│  │Badge│ │Badge│ │Badge│        │  ← 3×3 or 3×4 grid
│  │ #1  │ │ #2  │ │ #3  │        │
│  └─────┘ └─────┘ └─────┘        │
│  ┌─────┐ ┌─────┐ ┌─────┐        │
│  │Badge│ │Badge│ │Badge│        │
│  │ #4  │ │ #5  │ │ #6  │        │
│  └─────┘ └─────┘ └─────┘        │
├─────────────────────────────────┤
│  "12 achievements unlocked"     │  ← Summary count
│  [SportsTime logo + tagline]    │
└─────────────────────────────────┘
```

#### Type 3: Milestone Celebration

Same as Single Spotlight with:
- Animated particle/confetti burst pattern (static for image)
- Larger badge (500×500px)
- "MILESTONE" label above badge
- Gold accent elements regardless of theme

#### Type 4: Achievement + Context

```
┌─────────────────────────────────┐
│  ┌─────────┐                    │
│  │  BADGE  │  "Coast to Coast"  │  ← Badge + name side by side
│  └─────────┘   Unlocked!        │
├─────────────────────────────────┤
│                                 │
│    ┌─────────────────────┐      │
│    │   TRIP MAP or       │      │  ← Context: trip/visit
│    │   STADIUM PHOTO     │      │     that unlocked it
│    └─────────────────────┘      │
│                                 │
│  "Unlocked during my            │
│   Summer 2026 Road Trip"        │  ← Trip name or visit date
│                                 │
│  [SportsTime logo + tagline]    │
└─────────────────────────────────┘
```

### Stadium Progress Card

```
┌─────────────────────────────────┐
│  [Sport Icon]                   │
│  "MLB Stadium Quest"            │  ← Header
├─────────────────────────────────┤
│                                 │
│         ┌───────────┐           │
│        ╱             ╲          │
│       │      18      │          │  ← Progress ring: 320px
│       │    ────      │          │     Accent color fill
│       │   of 30      │          │
│        ╲             ╱          │
│         └───────────┘           │
│                                 │
│          60% Complete           │  ← Percentage
│                                 │
├─────────────────────────────────┤
│  ┌───────┐ ┌───────┐ ┌───────┐  │
│  │  18   │ │  12   │ │  4    │  │  ← Stats row
│  │visited│ │remain │ │trips  │  │
│  └───────┘ └───────┘ └───────┘  │
├─────────────────────────────────┤
│    ┌─────────────────────┐      │
│    │                     │      │
│    │   US MAP SNAPSHOT   │      │  ← Map: 500px height
│    │   ● visited (accent)│      │
│    │   ○ remaining (gray)│      │
│    │                     │      │
│    └─────────────────────┘      │
├─────────────────────────────────┤
│  @username (optional)           │  ← Optional username
│  [SportsTime logo + tagline]    │
└─────────────────────────────────┘
```

## Share UI/UX

### Contextual Share Buttons

`ShareButton` component appears on:
- Trip cards in saved trips list
- Trip detail view toolbar
- Achievement badges (on tap)
- Progress ring on Progress tab
- Achievement list header (for collection)

```swift
struct ShareButton: View {
    let content: ShareableContent
    @State private var showPreview = false

    var body: some View {
        Button {
            showPreview = true
        } label: {
            Image(systemName: "square.and.arrow.up")
        }
        .sheet(isPresented: $showPreview) {
            SharePreviewView(content: content)
        }
    }
}
```

### SharePreviewView

```
┌─────────────────────────────────┐
│  ← Cancel          Share →      │  ← Nav bar
├─────────────────────────────────┤
│                                 │
│    ┌─────────────────────┐      │
│    │                     │      │
│    │   LIVE PREVIEW      │      │  ← 40% scale preview
│    │   of card           │      │     Updates in real-time
│    │                     │      │
│    └─────────────────────┘      │
│                                 │
├─────────────────────────────────┤
│  Theme                          │
│  [Dark] [Light] [Midnight] ...  │  ← Horizontal scroll
├─────────────────────────────────┤
│  ☑ Include username             │  ← Toggle (progress only)
│  [@yourhandle____________]      │
├─────────────────────────────────┤
│                                 │
│  ┌─────────────────────────┐    │
│  │   Share to Instagram     │    │  ← Primary CTA
│  └─────────────────────────┘    │
│                                 │
│  [Copy Image]  [More Options]   │  ← Secondary actions
│                                 │
└─────────────────────────────────┘
```

### Instagram Integration

```swift
func shareToInstagram(image: UIImage) {
    guard let imageData = image.pngData() else { return }

    // Write to shared container for Instagram
    let pasteboardItems: [String: Any] = [
        "com.instagram.sharedSticker.backgroundImage": imageData
    ]

    UIPasteboard.general.setItems([pasteboardItems])

    // Open Instagram Stories
    if let url = URL(string: "instagram-stories://share?source_application=com.sportstime.app") {
        UIApplication.shared.open(url)
    }
}
```

Falls back to standard `UIActivityViewController` if Instagram not installed.

## File Structure

### Files to Delete

| File | Lines |
|------|-------|
| `SportsTime/Export/Services/ProgressCardGenerator.swift` | 607 |

### New Files

| File | Purpose | ~Lines |
|------|---------|--------|
| `Export/Sharing/ShareableContent.swift` | Protocol + ShareTheme | 120 |
| `Export/Sharing/ShareCardComponents.swift` | Header, footer, stats, map | 200 |
| `Export/Sharing/TripCardGenerator.swift` | Trip summary cards | 180 |
| `Export/Sharing/AchievementCardGenerator.swift` | All 4 achievement types | 350 |
| `Export/Sharing/ProgressCardGenerator.swift` | Stadium progress cards | 180 |
| `Export/Sharing/ShareService.swift` | Instagram, export, share sheet | 150 |
| `Export/Views/SharePreviewView.swift` | Unified preview UI | 250 |
| `Export/Views/ShareButton.swift` | Contextual button | 40 |

### Files to Modify

| File | Changes |
|------|---------|
| `TripDetailView.swift` | Replace `shareTrip()` with `ShareButton`, remove old `ShareSheet` |
| `ProgressTabView.swift` | Add `ShareButton` to progress rings |
| Achievement views | Add `ShareButton` to badges |

## Implementation Notes

### Map Snapshot Generation

Reuse pattern from existing code but extract to `ShareCardComponents`:

```swift
func generateRouteMapSnapshot(
    stops: [TripStop],
    theme: ShareTheme
) async -> UIImage? {
    // Calculate bounding region
    // Configure MKMapSnapshotter with theme-appropriate style
    // Draw route polyline in accent color
    // Draw city markers
}

func generateProgressMapSnapshot(
    visited: [Stadium],
    remaining: [Stadium],
    theme: ShareTheme
) async -> UIImage? {
    // Calculate US-wide region
    // Draw visited markers in accent color
    // Draw remaining markers in gray
}
```

### Image Rendering

Use SwiftUI `ImageRenderer` at 3x scale for high-res output:

```swift
func render(theme: ShareTheme) async throws -> UIImage {
    let cardView = TripCardView(trip: trip, theme: theme)
    let renderer = ImageRenderer(content: cardView)
    renderer.scale = 3.0

    guard let image = renderer.uiImage else {
        throw ShareError.renderingFailed
    }
    return image
}
```

### Theme Persistence

```swift
@AppStorage("shareTheme.trip") private var tripThemeId: String = "dark"
@AppStorage("shareTheme.achievement") private var achievementThemeId: String = "dark"
@AppStorage("shareTheme.progress") private var progressThemeId: String = "dark"
```

## Scope Summary

| Category | Count |
|----------|-------|
| New lines | ~1,470 |
| Deleted lines | ~607 |
| Modified lines | ~50 |
| New files | 8 |
| Deleted files | 1 |
| Modified files | 3+ |

## Success Criteria

- [ ] All 3 content types shareable (trips, achievements, progress)
- [ ] All 8 theme presets working
- [ ] Instagram Stories direct share working
- [ ] Fallback to share sheet when Instagram not installed
- [ ] Share buttons appear contextually throughout app
- [ ] Theme preference persisted per content type
- [ ] Cards render at 1080×1920 with proper scaling
