diff --git a/SportsTime/Features/Schedule/ViewModels/ScheduleViewModel.swift b/SportsTime/Features/Schedule/ViewModels/ScheduleViewModel.swift index 8a505b1..7be2438 100644 --- a/SportsTime/Features/Schedule/ViewModels/ScheduleViewModel.swift +++ b/SportsTime/Features/Schedule/ViewModels/ScheduleViewModel.swift @@ -26,6 +26,22 @@ final class ScheduleViewModel { private let dataProvider = AppDataProvider.shared + // MARK: - Pagination + + private let pageSize = 50 + private(set) var displayedGames: [RichGame] = [] + private var currentPage = 0 + private var allFilteredGames: [RichGame] = [] + + var hasMoreGames: Bool { + displayedGames.count < allFilteredGames.count + } + + /// The last game in the displayed list, used for infinite scroll detection + var lastDisplayedGame: RichGame? { + displayedGames.last + } + // MARK: - Computed Properties var filteredGames: [RichGame] { @@ -51,7 +67,7 @@ final class ScheduleViewModel { } var gamesBySport: [(sport: Sport, games: [RichGame])] { - let grouped = Dictionary(grouping: filteredGames) { game in + let grouped = Dictionary(grouping: displayedGames) { game in game.game.sport } // Sort by sport order (use allCases index for consistent ordering) @@ -69,11 +85,35 @@ final class ScheduleViewModel { selectedSports.count < Sport.supported.count || !searchText.isEmpty } + // MARK: - Pagination Actions + + /// Updates filtered games list based on current search text and resets pagination + func updateFilteredGames() { + allFilteredGames = filteredGames + loadInitialGames() + } + + /// Loads the first page of games + func loadInitialGames() { + currentPage = 0 + displayedGames = Array(allFilteredGames.prefix(pageSize)) + } + + /// Loads more games when scrolling to the bottom + func loadMoreGames() { + guard hasMoreGames else { return } + currentPage += 1 + let start = currentPage * pageSize + let end = min(start + pageSize, allFilteredGames.count) + displayedGames.append(contentsOf: allFilteredGames[start..