WIP: map route updates and custom item drag/drop fixes (broken)

- Fixed map header not updating in ItineraryTableViewWrapper using Coordinator pattern
- Added routeVersion UUID to force Map re-render when routes change
- Fixed determineAnchor to scan backwards for correct anchor context
- Added location support to CustomItineraryItem (lat/lng/address)
- Added MapKit place search to AddItemSheet
- Added extensive debug logging for route waypoint calculation

Known issues:
- Custom items still not routing correctly after drag/drop
- Anchor type determination may still have bugs

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Trey t
2026-01-17 00:00:57 -06:00
parent 43501b6ac1
commit 8df33a5614
7 changed files with 605 additions and 57 deletions

View File

@@ -436,21 +436,51 @@ final class ItineraryTableViewController: UITableViewController {
// MARK: - Helper Methods
private func determineAnchor(at row: Int) -> (CustomItineraryItem.AnchorType, String?) {
if row > 0 {
let previousItem = flatItems[row - 1]
switch previousItem {
// Scan backwards to find the day's context
// Structure: travel (optional) -> dayHeader -> items
var foundTravel: TravelSegment?
var foundDayGames: [RichGame] = []
for i in stride(from: row - 1, through: 0, by: -1) {
switch flatItems[i] {
case .travel(let segment, _):
// Found travel - if this is the first significant item, use afterTravel
// But only if we haven't passed a day header yet
if foundDayGames.isEmpty {
foundTravel = segment
}
// Travel marks the boundary - stop scanning
let travelId = "travel:\(segment.fromLocation.name.lowercased())->\(segment.toLocation.name.lowercased())"
return (.afterTravel, travelId)
// If the drop is right after travel (no day header between), use afterTravel
if foundDayGames.isEmpty {
return (.afterTravel, travelId)
}
// Otherwise we already passed a day header, use that context
break
case .dayHeader(_, _, let games):
// Found the day header for this section
foundDayGames = games
// If day has games, items dropped after should be afterGame
if let lastGame = games.last {
return (.afterGame, lastGame.game.id)
}
return (.startOfDay, nil)
default:
return (.startOfDay, nil)
// No games - check if there's travel before this day
// Continue scanning to find travel
continue
case .customItem, .addButton:
// Skip these, keep scanning backwards
continue
}
}
// If we found travel but no games, use afterTravel
if let segment = foundTravel {
let travelId = "travel:\(segment.fromLocation.name.lowercased())->\(segment.toLocation.name.lowercased())"
return (.afterTravel, travelId)
}
return (.startOfDay, nil)
}
@@ -664,10 +694,29 @@ struct CustomItemRowView: View {
Text(item.category.icon)
.font(.title3)
Text(item.title)
.font(.subheadline)
.foregroundStyle(Theme.textPrimary(colorScheme))
.lineLimit(2)
VStack(alignment: .leading, spacing: 2) {
HStack(spacing: 4) {
Text(item.title)
.font(.subheadline)
.foregroundStyle(Theme.textPrimary(colorScheme))
.lineLimit(1)
// Map pin for mappable items
if item.isMappable {
Image(systemName: "mappin.circle.fill")
.font(.caption)
.foregroundStyle(Theme.warmOrange)
}
}
// Address subtitle for mappable items
if let address = item.address, !address.isEmpty {
Text(address)
.font(.caption)
.foregroundStyle(Theme.textMuted(colorScheme))
.lineLimit(1)
}
}
Spacer()