Stabilize beta release with warning cleanup and edge-case fixes
This commit is contained in:
@@ -7,12 +7,13 @@
|
||||
// - Expected Behavior:
|
||||
// - itineraryDays() returns one ItineraryDay per calendar day from first arrival to last activity
|
||||
// - Last activity day includes departure day if there are games on that day
|
||||
// - tripDuration is max(1, days between first arrival and last departure + 1)
|
||||
// - tripDuration is 0 when there are no stops, otherwise max(1, days between first arrival and last departure + 1)
|
||||
// - cities returns deduplicated city list preserving visit order
|
||||
// - displayName uses " → " separator between cities
|
||||
//
|
||||
// - Invariants:
|
||||
// - tripDuration >= 1 (minimum 1 day)
|
||||
// - tripDuration >= 0
|
||||
// - tripDuration == 0 iff stops is empty
|
||||
// - cities has no duplicates
|
||||
// - itineraryDays() dayNumber starts at 1 and increments
|
||||
//
|
||||
|
||||
@@ -56,7 +56,8 @@ struct TripPoll: Identifiable, Codable, Hashable {
|
||||
private static let shareCodeCharacters = Array("ABCDEFGHJKMNPQRSTUVWXYZ23456789")
|
||||
|
||||
static func generateShareCode() -> String {
|
||||
String((0..<6).map { _ in shareCodeCharacters.randomElement()! })
|
||||
let fallback: Character = "A"
|
||||
return String((0..<6).map { _ in shareCodeCharacters.randomElement() ?? fallback })
|
||||
}
|
||||
|
||||
// MARK: - Trip Hash
|
||||
@@ -73,7 +74,11 @@ struct TripPoll: Identifiable, Codable, Hashable {
|
||||
// MARK: - Deep Link URL
|
||||
|
||||
var shareURL: URL {
|
||||
URL(string: "sportstime://poll/\(shareCode)")!
|
||||
var components = URLComponents()
|
||||
components.scheme = "sportstime"
|
||||
components.host = "poll"
|
||||
components.path = "/\(shareCode)"
|
||||
return components.url ?? URL(string: "sportstime://poll")!
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,9 +112,11 @@ struct PollVote: Identifiable, Codable, Hashable {
|
||||
/// Returns array where index = trip index, value = score
|
||||
static func calculateScores(rankings: [Int], tripCount: Int) -> [Int] {
|
||||
var scores = Array(repeating: 0, count: tripCount)
|
||||
var seenTripIndices = Set<Int>()
|
||||
for (rank, tripIndex) in rankings.enumerated() {
|
||||
guard tripIndex < tripCount else { continue }
|
||||
let points = tripCount - rank
|
||||
guard tripIndex >= 0, tripIndex < tripCount else { continue }
|
||||
guard seenTripIndices.insert(tripIndex).inserted else { continue }
|
||||
let points = max(tripCount - rank, 0)
|
||||
scores[tripIndex] = points
|
||||
}
|
||||
return scores
|
||||
|
||||
@@ -556,15 +556,6 @@ final class CanonicalSport {
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Sendable Conformance
|
||||
|
||||
// These SwiftData models are passed across actor boundaries during sync operations.
|
||||
// Access is still coordinated by SwiftData contexts and higher-level sync orchestration.
|
||||
extension StadiumAlias: @unchecked Sendable {}
|
||||
extension TeamAlias: @unchecked Sendable {}
|
||||
extension LeagueStructureModel: @unchecked Sendable {}
|
||||
extension CanonicalSport: @unchecked Sendable {}
|
||||
|
||||
// MARK: - Bundled Data Timestamps
|
||||
|
||||
/// Timestamps for bundled data files.
|
||||
|
||||
Reference in New Issue
Block a user