refactor(itinerary): replace anchor-based positioning with day/sortOrder

Replace complex anchor system (anchorType, anchorId, anchorDay) with
simple (day: Int, sortOrder: Double) positioning for custom items.

Changes:
- CustomItineraryItem: Remove anchor fields, add day and sortOrder
- CKModels: Add migration fallback from old CloudKit fields
- ItineraryTableViewController: Add calculateSortOrder() for midpoint insertion
- TripDetailView: Simplify callbacks, itinerarySections, and routeWaypoints
- AddItemSheet: Take simple day parameter instead of anchor
- SavedTrip: Update LocalCustomItem SwiftData model

Benefits:
- Items freely movable via drag-and-drop
- Route waypoints follow exact visual order
- Simpler mental model: position = (day, sortOrder)
- Midpoint insertion allows unlimited reordering

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Trey t
2026-01-17 09:47:11 -06:00
parent 59ba2c6965
commit 2a8bfeeff8
10 changed files with 238 additions and 385 deletions

View File

@@ -13,9 +13,7 @@ struct AddItemSheet: View {
@Environment(\.colorScheme) private var colorScheme
let tripId: UUID
let anchorDay: Int
let anchorType: CustomItineraryItem.AnchorType
let anchorId: String?
let day: Int
let existingItem: CustomItineraryItem?
var onSave: (CustomItineraryItem) -> Void
@@ -250,7 +248,7 @@ struct AddItemSheet: View {
let item: CustomItineraryItem
if let existing = existingItem {
// Editing existing item
// Editing existing item - preserve day and sortOrder
let trimmedTitle = title.trimmingCharacters(in: .whitespaces)
guard !trimmedTitle.isEmpty else { return }
@@ -259,9 +257,7 @@ struct AddItemSheet: View {
tripId: existing.tripId,
category: selectedCategory,
title: trimmedTitle,
anchorType: existing.anchorType,
anchorId: existing.anchorId,
anchorDay: existing.anchorDay,
day: existing.day,
sortOrder: existing.sortOrder,
createdAt: existing.createdAt,
modifiedAt: Date(),
@@ -274,13 +270,13 @@ struct AddItemSheet: View {
let placeName = place.name ?? "Unknown Place"
let coordinate = place.placemark.coordinate
// New items get sortOrder 0 (will be placed at beginning, caller can adjust)
item = CustomItineraryItem(
tripId: tripId,
category: selectedCategory,
title: placeName,
anchorType: anchorType,
anchorId: anchorId,
anchorDay: anchorDay,
day: day,
sortOrder: 0.0,
latitude: coordinate.latitude,
longitude: coordinate.longitude,
address: formatAddress(for: place)
@@ -290,13 +286,13 @@ struct AddItemSheet: View {
let trimmedTitle = title.trimmingCharacters(in: .whitespaces)
guard !trimmedTitle.isEmpty else { return }
// New items get sortOrder 0 (will be placed at beginning, caller can adjust)
item = CustomItineraryItem(
tripId: tripId,
category: selectedCategory,
title: trimmedTitle,
anchorType: anchorType,
anchorId: anchorId,
anchorDay: anchorDay
day: day,
sortOrder: 0.0
)
}
@@ -385,9 +381,7 @@ private struct CategoryButton: View {
#Preview {
AddItemSheet(
tripId: UUID(),
anchorDay: 1,
anchorType: .startOfDay,
anchorId: nil,
day: 1,
existingItem: nil
) { _ in }
}