Restore Live shelf on Today, flatten Feed to time-ordered highlights
Today tab: Removed LiveSituationBar, restored the full Live game shelf below the featured Astros card where it belongs. Feed tab: Changed from two grouped shelves (condensed / highlights) to a single horizontal scroll with ALL highlights ordered by timestamp (most recent first). Added condensed game badge overlay on thumbnails. Added date field to Highlight model for time-based ordering. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -9,6 +9,15 @@ private func logFeed(_ message: String) {
|
||||
print("[Feed] \(message)")
|
||||
}
|
||||
|
||||
private func parseHighlightDate(_ string: String?) -> Date? {
|
||||
guard let string else { return nil }
|
||||
let iso = ISO8601DateFormatter()
|
||||
iso.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
|
||||
if let d = iso.date(from: string) { return d }
|
||||
iso.formatOptions = [.withInternetDateTime]
|
||||
return iso.date(from: string)
|
||||
}
|
||||
|
||||
struct HighlightItem: Identifiable, Sendable {
|
||||
let id: String
|
||||
let headline: String
|
||||
@@ -18,6 +27,7 @@ struct HighlightItem: Identifiable, Sendable {
|
||||
let hlsURL: URL?
|
||||
let mp4URL: URL?
|
||||
let isCondensedGame: Bool
|
||||
let timestamp: Date
|
||||
}
|
||||
|
||||
@Observable
|
||||
@@ -37,7 +47,6 @@ final class FeedViewModel {
|
||||
|
||||
let gamesWithPk = games.filter { $0.gamePk != nil }
|
||||
|
||||
// Fetch highlights for all games concurrently
|
||||
await withTaskGroup(of: [HighlightItem].self) { group in
|
||||
for game in gamesWithPk {
|
||||
group.addTask { [serverAPI] in
|
||||
@@ -46,7 +55,7 @@ final class FeedViewModel {
|
||||
gamePk: game.gamePk!,
|
||||
gameDate: game.gameDate
|
||||
)
|
||||
return raw.compactMap { highlight -> HighlightItem? in
|
||||
return raw.enumerated().compactMap { index, highlight -> HighlightItem? in
|
||||
guard let headline = highlight.headline,
|
||||
let hlsStr = highlight.hlsURL ?? highlight.mp4URL,
|
||||
let _ = URL(string: hlsStr) else { return nil }
|
||||
@@ -54,15 +63,19 @@ final class FeedViewModel {
|
||||
let isCondensed = headline.lowercased().contains("condensed")
|
||||
|| headline.lowercased().contains("recap")
|
||||
|
||||
let timestamp = parseHighlightDate(highlight.date)
|
||||
?? Date(timeIntervalSince1970: TimeInterval(index))
|
||||
|
||||
return HighlightItem(
|
||||
id: highlight.id ?? UUID().uuidString,
|
||||
id: highlight.id ?? "\(game.gamePk!)-\(index)",
|
||||
headline: headline,
|
||||
gameTitle: "\(game.awayTeam.code) @ \(game.homeTeam.code)",
|
||||
awayCode: game.awayTeam.code,
|
||||
homeCode: game.homeTeam.code,
|
||||
hlsURL: highlight.hlsURL.flatMap(URL.init),
|
||||
mp4URL: highlight.mp4URL.flatMap(URL.init),
|
||||
isCondensedGame: isCondensed
|
||||
isCondensedGame: isCondensed,
|
||||
timestamp: timestamp
|
||||
)
|
||||
}
|
||||
} catch {
|
||||
@@ -75,7 +88,8 @@ final class FeedViewModel {
|
||||
for await batch in group {
|
||||
allHighlights.append(contentsOf: batch)
|
||||
}
|
||||
highlights = allHighlights
|
||||
// Sort all highlights by time, most recent first
|
||||
highlights = allHighlights.sorted { $0.timestamp > $1.timestamp }
|
||||
}
|
||||
|
||||
isLoading = false
|
||||
|
||||
Reference in New Issue
Block a user