fix: standardize trip name display with arrow separators app-wide
- Add `displayName` computed property to Trip model that always generates city list with " → " separator for consistent display - Replace all `trip.name` usages with `trip.displayName` in UI files - Update SuggestedTripsGenerator to use " → " separator - Update PDFGenerator to use displayName for PDF titles This ensures all trip names display consistently regardless of when the trip was created or how the name was originally stored. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -70,6 +70,13 @@ struct Trip: Identifiable, Codable, Hashable {
|
||||
return stop.city
|
||||
}
|
||||
}
|
||||
|
||||
/// Display name generated from cities - always uses " → " separator for consistency
|
||||
var displayName: String {
|
||||
let cityList = cities
|
||||
return cityList.isEmpty ? name : cityList.joined(separator: " → ")
|
||||
}
|
||||
|
||||
var uniqueSports: Set<Sport> { preferences.sports }
|
||||
var startDate: Date { stops.first?.arrivalDate ?? preferences.startDate }
|
||||
var endDate: Date { stops.last?.departureDate ?? preferences.endDate }
|
||||
|
||||
@@ -584,7 +584,7 @@ final class SuggestedTripsGenerator {
|
||||
if cities.count <= 1 {
|
||||
return cities.first ?? "Road Trip"
|
||||
}
|
||||
return cities.joined(separator: " - ")
|
||||
return cities.joined(separator: " → ")
|
||||
}
|
||||
|
||||
// MARK: - Corridor Trip Building
|
||||
|
||||
@@ -103,7 +103,7 @@ final class PDFGenerator {
|
||||
.foregroundColor: UIColor.black
|
||||
]
|
||||
let titleRect = CGRect(x: margin, y: y, width: contentWidth, height: 50)
|
||||
(trip.name as NSString).draw(in: titleRect, withAttributes: titleAttributes)
|
||||
(trip.displayName as NSString).draw(in: titleRect, withAttributes: titleAttributes)
|
||||
y += 55
|
||||
|
||||
// Date range
|
||||
|
||||
@@ -329,7 +329,7 @@ struct SavedTripCard: View {
|
||||
}
|
||||
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
Text(trip.name)
|
||||
Text(trip.displayName)
|
||||
.font(.body)
|
||||
.foregroundStyle(Theme.textPrimary(colorScheme))
|
||||
|
||||
@@ -653,7 +653,7 @@ struct SavedTripListRow: View {
|
||||
.frame(width: 20)
|
||||
|
||||
VStack(alignment: .leading, spacing: Theme.Spacing.xs) {
|
||||
Text(trip.name)
|
||||
Text(trip.displayName)
|
||||
.font(.headline)
|
||||
.foregroundStyle(Theme.textPrimary(colorScheme))
|
||||
|
||||
|
||||
@@ -215,7 +215,7 @@ struct HomeContent_Airbnb: View {
|
||||
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
HStack {
|
||||
Text(trip.name)
|
||||
Text(trip.displayName)
|
||||
.font(.system(size: 14, weight: .medium))
|
||||
.foregroundStyle(textPrimary)
|
||||
.lineLimit(1)
|
||||
@@ -302,7 +302,7 @@ struct HomeContent_Airbnb: View {
|
||||
)
|
||||
|
||||
VStack(alignment: .leading, spacing: 6) {
|
||||
Text(trip.name)
|
||||
Text(trip.displayName)
|
||||
.font(.system(size: 15, weight: .medium))
|
||||
.foregroundStyle(textPrimary)
|
||||
.lineLimit(1)
|
||||
|
||||
@@ -154,7 +154,7 @@ struct HomeContent_AppleMaps: View {
|
||||
}
|
||||
|
||||
VStack(alignment: .leading, spacing: 3) {
|
||||
Text(trip.name)
|
||||
Text(trip.displayName)
|
||||
.font(.system(size: 16))
|
||||
.foregroundStyle(textPrimary)
|
||||
.lineLimit(1)
|
||||
@@ -239,7 +239,7 @@ struct HomeContent_AppleMaps: View {
|
||||
}
|
||||
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
Text(trip.name)
|
||||
Text(trip.displayName)
|
||||
.font(.system(size: 14, weight: .medium))
|
||||
.foregroundStyle(textPrimary)
|
||||
.lineLimit(2)
|
||||
|
||||
@@ -347,7 +347,7 @@ struct HomeContent_ArtDeco: View {
|
||||
}
|
||||
|
||||
VStack(alignment: .leading, spacing: 6) {
|
||||
Text(trip.name.uppercased())
|
||||
Text(trip.displayName.uppercased())
|
||||
.font(.system(size: 14, weight: .bold))
|
||||
.tracking(1)
|
||||
.foregroundStyle(textPrimary)
|
||||
@@ -430,7 +430,7 @@ struct HomeContent_ArtDeco: View {
|
||||
decoDiamond
|
||||
.foregroundStyle(decoTeal)
|
||||
|
||||
Text(trip.name)
|
||||
Text(trip.displayName)
|
||||
.font(.system(size: 14, weight: .medium))
|
||||
.foregroundStyle(textPrimary)
|
||||
|
||||
|
||||
@@ -169,7 +169,7 @@ struct HomeContent_Brutalist: View {
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
HStack(alignment: .top) {
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
Text(trip.name.uppercased())
|
||||
Text(trip.displayName.uppercased())
|
||||
.font(.system(.headline, design: .monospaced).bold())
|
||||
.foregroundStyle(textColor)
|
||||
|
||||
@@ -227,7 +227,7 @@ struct HomeContent_Brutalist: View {
|
||||
TripDetailView(trip: trip)
|
||||
} label: {
|
||||
HStack {
|
||||
Text(trip.name.uppercased())
|
||||
Text(trip.displayName.uppercased())
|
||||
.font(.system(.subheadline, design: .monospaced))
|
||||
.foregroundStyle(textColor)
|
||||
|
||||
|
||||
@@ -240,7 +240,7 @@ struct HomeContent_CarrotWeather: View {
|
||||
)
|
||||
|
||||
VStack(alignment: .leading, spacing: 3) {
|
||||
Text(trip.name)
|
||||
Text(trip.displayName)
|
||||
.font(.system(size: 15, weight: .medium))
|
||||
.foregroundStyle(textPrimary)
|
||||
.lineLimit(1)
|
||||
@@ -323,7 +323,7 @@ struct HomeContent_CarrotWeather: View {
|
||||
.padding(.vertical, 12)
|
||||
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
Text(trip.name)
|
||||
Text(trip.displayName)
|
||||
.font(.system(size: 13, weight: .medium))
|
||||
.foregroundStyle(textPrimary)
|
||||
.lineLimit(2)
|
||||
|
||||
@@ -231,7 +231,7 @@ struct HomeContent_Classic: View {
|
||||
}
|
||||
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
Text(trip.name)
|
||||
Text(trip.displayName)
|
||||
.font(.body)
|
||||
.foregroundStyle(Theme.textPrimary(colorScheme))
|
||||
|
||||
|
||||
@@ -306,7 +306,7 @@ struct HomeContent_DarkIndustrial: View {
|
||||
.background(warningYellow)
|
||||
|
||||
VStack(alignment: .leading, spacing: 6) {
|
||||
Text(trip.name.uppercased())
|
||||
Text(trip.displayName.uppercased())
|
||||
.font(.system(size: 13, weight: .bold, design: .monospaced))
|
||||
.foregroundStyle(textPrimary)
|
||||
.lineLimit(1)
|
||||
@@ -383,7 +383,7 @@ struct HomeContent_DarkIndustrial: View {
|
||||
.fill(steelGray.opacity(0.5))
|
||||
.frame(width: 3, height: 32)
|
||||
|
||||
Text(trip.name.uppercased())
|
||||
Text(trip.displayName.uppercased())
|
||||
.font(.system(size: 12, weight: .medium, design: .monospaced))
|
||||
.foregroundStyle(textPrimary)
|
||||
|
||||
|
||||
@@ -207,7 +207,7 @@ struct HomeContent_Fantastical: View {
|
||||
.frame(width: 4, height: 44)
|
||||
|
||||
VStack(alignment: .leading, spacing: 3) {
|
||||
Text(trip.name)
|
||||
Text(trip.displayName)
|
||||
.font(.system(size: 15, weight: .medium))
|
||||
.foregroundStyle(textPrimary)
|
||||
.lineLimit(1)
|
||||
@@ -297,7 +297,7 @@ struct HomeContent_Fantastical: View {
|
||||
)
|
||||
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
Text(trip.name)
|
||||
Text(trip.displayName)
|
||||
.font(.system(size: 15, weight: .medium))
|
||||
.foregroundStyle(textPrimary)
|
||||
.lineLimit(1)
|
||||
|
||||
@@ -221,7 +221,7 @@ struct HomeContent_Flighty: View {
|
||||
}
|
||||
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
Text(trip.name)
|
||||
Text(trip.displayName)
|
||||
.font(.system(size: 16, weight: .semibold))
|
||||
.foregroundStyle(textPrimary)
|
||||
.lineLimit(1)
|
||||
@@ -310,7 +310,7 @@ struct HomeContent_Flighty: View {
|
||||
}
|
||||
|
||||
VStack(alignment: .leading, spacing: 3) {
|
||||
Text(trip.name)
|
||||
Text(trip.displayName)
|
||||
.font(.system(size: 15, weight: .medium))
|
||||
.foregroundStyle(textPrimary)
|
||||
.lineLimit(1)
|
||||
|
||||
@@ -224,7 +224,7 @@ struct HomeContent_Glassmorphism: View {
|
||||
}
|
||||
}
|
||||
|
||||
Text(trip.name)
|
||||
Text(trip.displayName)
|
||||
.font(.system(size: 16, weight: .semibold, design: .rounded))
|
||||
.foregroundStyle(colorScheme == .dark ? .white : Color(white: 0.15))
|
||||
.lineLimit(2)
|
||||
@@ -306,7 +306,7 @@ struct HomeContent_Glassmorphism: View {
|
||||
}
|
||||
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
Text(trip.name)
|
||||
Text(trip.displayName)
|
||||
.font(.system(size: 15, weight: .medium, design: .rounded))
|
||||
.foregroundStyle(colorScheme == .dark ? .white : Color(white: 0.15))
|
||||
|
||||
|
||||
@@ -227,7 +227,7 @@ struct HomeContent_LuxuryEditorial: View {
|
||||
}
|
||||
|
||||
// Title
|
||||
Text(trip.name)
|
||||
Text(trip.displayName)
|
||||
.font(.system(size: 18, weight: .regular, design: .serif))
|
||||
.foregroundStyle(textPrimary)
|
||||
.lineLimit(2)
|
||||
@@ -293,7 +293,7 @@ struct HomeContent_LuxuryEditorial: View {
|
||||
.frame(width: 20)
|
||||
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
Text(trip.name)
|
||||
Text(trip.displayName)
|
||||
.font(.system(size: 16, weight: .regular, design: .serif))
|
||||
.foregroundStyle(textPrimary)
|
||||
|
||||
|
||||
@@ -324,7 +324,7 @@ struct HomeContent_MaximalistChaos: View {
|
||||
}
|
||||
|
||||
VStack(alignment: .leading, spacing: 6) {
|
||||
Text(trip.name)
|
||||
Text(trip.displayName)
|
||||
.font(.system(size: 16, weight: .bold, design: .rounded))
|
||||
.foregroundStyle(colorScheme == .dark ? .white : .black)
|
||||
.lineLimit(1)
|
||||
@@ -402,7 +402,7 @@ struct HomeContent_MaximalistChaos: View {
|
||||
.fill(accentColor)
|
||||
.frame(width: 6)
|
||||
|
||||
Text(trip.name)
|
||||
Text(trip.displayName)
|
||||
.font(.system(size: 14, weight: .semibold, design: .rounded))
|
||||
.foregroundStyle(colorScheme == .dark ? .white : .black)
|
||||
|
||||
|
||||
@@ -230,7 +230,7 @@ struct HomeContent_NeoBrutalist: View {
|
||||
.frame(width: 8)
|
||||
|
||||
VStack(alignment: .leading, spacing: 6) {
|
||||
Text(trip.name.uppercased())
|
||||
Text(trip.displayName.uppercased())
|
||||
.font(.system(size: 14, weight: .black))
|
||||
.foregroundStyle(textColor)
|
||||
.lineLimit(1)
|
||||
@@ -297,7 +297,7 @@ struct HomeContent_NeoBrutalist: View {
|
||||
.fill(electricBlue)
|
||||
.frame(width: 4)
|
||||
|
||||
Text(trip.name.uppercased())
|
||||
Text(trip.displayName.uppercased())
|
||||
.font(.system(size: 13, weight: .bold))
|
||||
.foregroundStyle(textColor)
|
||||
|
||||
|
||||
@@ -194,7 +194,7 @@ struct HomeContent_NikeRunClub: View {
|
||||
}
|
||||
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
Text(trip.name)
|
||||
Text(trip.displayName)
|
||||
.font(.system(size: 16, weight: .semibold))
|
||||
.foregroundStyle(textPrimary)
|
||||
.lineLimit(1)
|
||||
@@ -278,7 +278,7 @@ struct HomeContent_NikeRunClub: View {
|
||||
}
|
||||
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
Text(trip.name)
|
||||
Text(trip.displayName)
|
||||
.font(.system(size: 14, weight: .semibold))
|
||||
.foregroundStyle(textPrimary)
|
||||
.lineLimit(1)
|
||||
|
||||
@@ -195,7 +195,7 @@ struct HomeContent_Organic: View {
|
||||
}
|
||||
|
||||
VStack(alignment: .leading, spacing: 6) {
|
||||
Text(trip.name)
|
||||
Text(trip.displayName)
|
||||
.font(.system(size: 16, weight: .semibold, design: .rounded))
|
||||
.foregroundStyle(textPrimary)
|
||||
.lineLimit(1)
|
||||
@@ -269,7 +269,7 @@ struct HomeContent_Organic: View {
|
||||
.frame(width: 24, height: 24)
|
||||
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
Text(trip.name)
|
||||
Text(trip.displayName)
|
||||
.font(.system(size: 15, weight: .medium, design: .rounded))
|
||||
.foregroundStyle(textPrimary)
|
||||
|
||||
|
||||
@@ -240,7 +240,7 @@ struct HomeContent_Playful: View {
|
||||
}
|
||||
|
||||
VStack(alignment: .leading, spacing: 6) {
|
||||
Text(trip.name)
|
||||
Text(trip.displayName)
|
||||
.font(.system(size: 16, weight: .semibold, design: .rounded))
|
||||
.foregroundStyle(colorScheme == .dark ? .white : Color(white: 0.15))
|
||||
.lineLimit(1)
|
||||
@@ -321,7 +321,7 @@ struct HomeContent_Playful: View {
|
||||
)
|
||||
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
Text(trip.name)
|
||||
Text(trip.displayName)
|
||||
.font(.system(size: 15, weight: .medium, design: .rounded))
|
||||
.foregroundStyle(colorScheme == .dark ? .white : Color(white: 0.15))
|
||||
|
||||
|
||||
@@ -237,7 +237,7 @@ struct HomeContent_RetroFuturism: View {
|
||||
.shadow(color: trip.uniqueSports.first?.themeColor.opacity(0.5) ?? neonCyan.opacity(0.5), radius: 10)
|
||||
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
Text(trip.name.uppercased())
|
||||
Text(trip.displayName.uppercased())
|
||||
.font(.system(size: 14, weight: .bold, design: .rounded))
|
||||
.foregroundStyle(chrome)
|
||||
|
||||
@@ -306,7 +306,7 @@ struct HomeContent_RetroFuturism: View {
|
||||
TripDetailView(trip: trip)
|
||||
} label: {
|
||||
HStack {
|
||||
Text(trip.name)
|
||||
Text(trip.displayName)
|
||||
.font(.system(size: 13, weight: .medium, design: .rounded))
|
||||
.foregroundStyle(chrome.opacity(0.8))
|
||||
|
||||
|
||||
@@ -197,7 +197,7 @@ struct HomeContent_SeatGeek: View {
|
||||
Spacer()
|
||||
}
|
||||
|
||||
Text(trip.name)
|
||||
Text(trip.displayName)
|
||||
.font(.system(size: 15, weight: .semibold))
|
||||
.foregroundStyle(textPrimary)
|
||||
.lineLimit(2)
|
||||
@@ -286,7 +286,7 @@ struct HomeContent_SeatGeek: View {
|
||||
}
|
||||
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
Text(trip.name)
|
||||
Text(trip.displayName)
|
||||
.font(.system(size: 15, weight: .semibold))
|
||||
.foregroundStyle(textPrimary)
|
||||
.lineLimit(1)
|
||||
|
||||
@@ -260,7 +260,7 @@ struct HomeContent_SoftPastel: View {
|
||||
)
|
||||
|
||||
VStack(alignment: .leading, spacing: 6) {
|
||||
Text(trip.name)
|
||||
Text(trip.displayName)
|
||||
.font(.system(size: 16, weight: .medium, design: .rounded))
|
||||
.foregroundStyle(textPrimary)
|
||||
.lineLimit(1)
|
||||
@@ -333,7 +333,7 @@ struct HomeContent_SoftPastel: View {
|
||||
.frame(width: 12, height: 12)
|
||||
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
Text(trip.name)
|
||||
Text(trip.displayName)
|
||||
.font(.system(size: 15, weight: .medium, design: .rounded))
|
||||
.foregroundStyle(textPrimary)
|
||||
|
||||
|
||||
@@ -144,7 +144,7 @@ struct HomeContent_Spotify: View {
|
||||
.shadow(color: Color.black.opacity(0.4), radius: 8, y: 4)
|
||||
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
Text(trip.name)
|
||||
Text(trip.displayName)
|
||||
.font(.system(size: 14, weight: .semibold))
|
||||
.foregroundStyle(textPrimary)
|
||||
.lineLimit(1)
|
||||
@@ -213,7 +213,7 @@ struct HomeContent_Spotify: View {
|
||||
.shadow(color: Color.black.opacity(0.4), radius: 8, y: 4)
|
||||
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
Text(trip.name)
|
||||
Text(trip.displayName)
|
||||
.font(.system(size: 14, weight: .semibold))
|
||||
.foregroundStyle(textPrimary)
|
||||
.lineLimit(2)
|
||||
|
||||
@@ -236,7 +236,7 @@ struct HomeContent_Strava: View {
|
||||
)
|
||||
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
Text(trip.name)
|
||||
Text(trip.displayName)
|
||||
.font(.system(size: 15, weight: .semibold))
|
||||
.foregroundStyle(textPrimary)
|
||||
.lineLimit(1)
|
||||
@@ -351,7 +351,7 @@ struct HomeContent_Strava: View {
|
||||
}
|
||||
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
Text(trip.name)
|
||||
Text(trip.displayName)
|
||||
.font(.system(size: 13, weight: .semibold))
|
||||
.foregroundStyle(textPrimary)
|
||||
.lineLimit(1)
|
||||
|
||||
@@ -228,7 +228,7 @@ struct HomeContent_SwissModernist: View {
|
||||
.frame(width: 24)
|
||||
|
||||
// Trip name
|
||||
Text(trip.name)
|
||||
Text(trip.displayName)
|
||||
.font(.system(size: 15, weight: .medium))
|
||||
.foregroundStyle(textPrimary)
|
||||
.lineLimit(1)
|
||||
@@ -314,7 +314,7 @@ struct HomeContent_SwissModernist: View {
|
||||
.frame(width: 24)
|
||||
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
Text(trip.name)
|
||||
Text(trip.displayName)
|
||||
.font(.system(size: 15, weight: .medium))
|
||||
.foregroundStyle(textPrimary)
|
||||
|
||||
|
||||
@@ -188,7 +188,7 @@ struct HomeContent_Things3: View {
|
||||
.frame(width: 22, height: 22)
|
||||
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
Text(trip.name)
|
||||
Text(trip.displayName)
|
||||
.font(.system(size: 17))
|
||||
.foregroundStyle(textPrimary)
|
||||
.lineLimit(1)
|
||||
@@ -279,7 +279,7 @@ struct HomeContent_Things3: View {
|
||||
)
|
||||
|
||||
VStack(alignment: .leading, spacing: 3) {
|
||||
Text(trip.name)
|
||||
Text(trip.displayName)
|
||||
.font(.system(size: 17))
|
||||
.foregroundStyle(textPrimary)
|
||||
.lineLimit(1)
|
||||
|
||||
@@ -101,7 +101,7 @@ private struct TripSelectionRow: View {
|
||||
Button(action: onTap) {
|
||||
HStack {
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
Text(trip.name)
|
||||
Text(trip.displayName)
|
||||
.font(.headline)
|
||||
.foregroundStyle(.primary)
|
||||
|
||||
|
||||
@@ -274,7 +274,7 @@ struct PollDetailView: View {
|
||||
let rank = results.tripScores.firstIndex { $0.tripIndex == item.tripIndex }! + 1
|
||||
ResultRow(
|
||||
rank: rank,
|
||||
tripName: trip.name,
|
||||
tripName: trip.displayName,
|
||||
score: item.score,
|
||||
percentage: results.scorePercentage(for: item.tripIndex),
|
||||
isLeader: rank == 1 && item.score > 0
|
||||
@@ -420,7 +420,7 @@ private struct TripPreviewCard: View {
|
||||
.background(Theme.warmOrange)
|
||||
.clipShape(Capsule())
|
||||
|
||||
Text(trip.name)
|
||||
Text(trip.displayName)
|
||||
.font(.headline)
|
||||
.foregroundStyle(.primary)
|
||||
}
|
||||
@@ -441,12 +441,6 @@ private struct TripPreviewCard: View {
|
||||
}
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
|
||||
// Show cities
|
||||
Text(trip.stops.map { $0.city }.joined(separator: " → "))
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
.lineLimit(2)
|
||||
}
|
||||
|
||||
Image(systemName: "chevron.right")
|
||||
|
||||
@@ -138,7 +138,7 @@ private struct RankingRow: View {
|
||||
.clipShape(Circle())
|
||||
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
Text(trip.name)
|
||||
Text(trip.displayName)
|
||||
.font(.headline)
|
||||
|
||||
Text(tripSummary)
|
||||
|
||||
Reference in New Issue
Block a user