feat(itinerary): add custom itinerary items with drag-to-reorder

- Add CustomItineraryItem domain model with sortOrder for ordering
- Add CKCustomItineraryItem CloudKit wrapper for persistence
- Create CustomItemService for CRUD operations
- Create CustomItemSubscriptionService for real-time sync
- Add AppDelegate for push notification handling
- Add AddItemSheet for creating/editing items
- Add CustomItemRow with drag handle
- Update TripDetailView with continuous vertical timeline
- Enable drag-to-reorder using .draggable/.dropDestination
- Add inline "Add" buttons after games and travel segments

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Trey t
2026-01-16 00:31:44 -06:00
parent b534ca771b
commit 495ef88303
13 changed files with 1302 additions and 33 deletions

View File

@@ -0,0 +1,83 @@
//
// CustomItineraryItem.swift
// SportsTime
//
import Foundation
struct CustomItineraryItem: Identifiable, Codable, Hashable {
let id: UUID
let tripId: UUID
var category: ItemCategory
var title: String
var anchorType: AnchorType
var anchorId: String?
var anchorDay: Int
var sortOrder: Int // For ordering within same anchor position
let createdAt: Date
var modifiedAt: Date
init(
id: UUID = UUID(),
tripId: UUID,
category: ItemCategory,
title: String,
anchorType: AnchorType = .startOfDay,
anchorId: String? = nil,
anchorDay: Int,
sortOrder: Int = 0,
createdAt: Date = Date(),
modifiedAt: Date = Date()
) {
self.id = id
self.tripId = tripId
self.category = category
self.title = title
self.anchorType = anchorType
self.anchorId = anchorId
self.anchorDay = anchorDay
self.sortOrder = sortOrder
self.createdAt = createdAt
self.modifiedAt = modifiedAt
}
enum ItemCategory: String, Codable, CaseIterable {
case restaurant
case hotel
case activity
case note
var icon: String {
switch self {
case .restaurant: return "🍽️"
case .hotel: return "🏨"
case .activity: return "🎯"
case .note: return "📝"
}
}
var label: String {
switch self {
case .restaurant: return "Restaurant"
case .hotel: return "Hotel"
case .activity: return "Activity"
case .note: return "Note"
}
}
var systemImage: String {
switch self {
case .restaurant: return "fork.knife"
case .hotel: return "bed.double.fill"
case .activity: return "figure.run"
case .note: return "note.text"
}
}
}
enum AnchorType: String, Codable {
case startOfDay
case afterGame
case afterTravel
}
}