@@ -2,10 +2,12 @@ package com.cornellappdev.score.model
22
33import android.util.Log
44import com.apollographql.apollo.ApolloClient
5+ import com.apollographql.apollo.exception.ApolloException
56import com.cornellappdev.score.util.isValidSport
67import com.cornellappdev.score.util.parseColor
78import com.example.score.GameByIdQuery
89import com.example.score.GamesQuery
10+ import com.example.score.PagedGamesQuery
911import kotlinx.coroutines.CoroutineScope
1012import kotlinx.coroutines.flow.MutableStateFlow
1113import kotlinx.coroutines.flow.asStateFlow
@@ -36,11 +38,17 @@ class ScoreRepository @Inject constructor(
3638 MutableStateFlow <ApiResponse <GameDetailsGame >>(ApiResponse .Loading )
3739 val currentGamesFlow = _currentGameFlow .asStateFlow()
3840
41+ companion object {
42+ private const val PAGE_LIMIT = 100
43+ private const val MAX_RETRIES = 3
44+ private const val PAGE_TIMEOUT_MILLIS = 3000L
45+ }
46+
3947 /* *
4048 * Asynchronously fetches the list of games from the API. Once finished, will send down
4149 * `upcomingGamesFlow` to be observed.
4250 */
43- fun fetchGames () = appScope.launch {
51+ fun fetchGamesPrev () = appScope.launch {
4452 _upcomingGamesFlow .value = ApiResponse .Loading
4553 try {
4654 val result =
@@ -92,33 +100,113 @@ class ScoreRepository @Inject constructor(
92100 }
93101 }
94102
103+ fun fetchGames () = appScope.launch {
104+ _upcomingGamesFlow .value = ApiResponse .Loading
105+ val allGames = mutableListOf<Game >()
106+ var offset = 0
107+ var retries = 0
108+
109+ try {
110+ while (true ) {
111+ val pageResult: List <PagedGamesQuery .Game ?>? = try {
112+ withTimeout(PAGE_TIMEOUT_MILLIS ) {
113+ apolloClient.query(PagedGamesQuery (limit = PAGE_LIMIT , offset = offset))
114+ .execute()
115+ .data
116+ ?.games
117+ }
118+ } catch (e: Exception ) {
119+ null
120+ }
121+
122+ if (pageResult == null ) {
123+ if (retries < MAX_RETRIES ) {
124+ retries++
125+ continue
126+ } else {
127+ break
128+ }
129+ }
130+
131+ if (pageResult.isEmpty()) {
132+ break
133+ }
134+
135+ retries = 0
136+
137+ val pageGames: List <Game > = pageResult
138+ .filterNotNull()
139+ .filter { gql -> isValidSport(gql.sport ? : " " ) }
140+ .mapNotNull { gql ->
141+ val scores = gql.result?.split(" ," )?.getOrNull(1 )?.split(" -" )
142+ val cornellScore = scores?.getOrNull(0 )?.toNumberOrNull()
143+ val otherScore = scores?.getOrNull(1 )?.toNumberOrNull()
144+ gql.team?.image?.let { imageUrl ->
145+ Game (
146+ id = gql.id ? : " " ,
147+ teamLogo = imageUrl,
148+ teamName = gql.team.name,
149+ teamColor = parseColor(gql.team.color).copy(alpha = 0.4f * 255 ),
150+ gender = if (gql.gender == " Mens" ) " Men's" else " Women's" ,
151+ sport = gql.sport,
152+ date = gql.date,
153+ city = gql.city,
154+ cornellScore = cornellScore,
155+ otherScore = otherScore
156+ )
157+ }
158+ }
159+
160+ allGames.addAll(pageGames)
161+
162+ if (pageResult.size < PAGE_LIMIT ) break
163+ offset + = PAGE_LIMIT
164+ }
165+
166+ _upcomingGamesFlow .value =
167+ if (allGames.isNotEmpty()) ApiResponse .Success (allGames)
168+ else ApiResponse .Error
169+
170+ } catch (e: Exception ) {
171+ Log .e(" ScoreRepository" , " Error fetching upcoming games" , e)
172+ _upcomingGamesFlow .value = ApiResponse .Error
173+ }
174+ }
175+
95176 /* *
96177 * Asynchronously fetches game details for a particular game. Once finished, will update
97178 * `currentGamesFlow` to be observed.
98179 */
99180 fun getGameById (id : String ) = appScope.launch {
100181 _currentGameFlow .value = ApiResponse .Loading
101182 try {
102- val result =
183+ val response =
103184 withTimeout(TIMEOUT_TIME_MILLIS ) {
104- apolloClient.query(GameByIdQuery (id)).execute().toResult()
185+ apolloClient.query(GameByIdQuery (id)).execute()
105186 }
106187
188+ if (response.hasErrors()) {
189+ Log .e(" ScoreRepository" , " Error fetching game with id: $id : ${response.errors} " )
190+ _currentGameFlow .value = ApiResponse .Error
191+ return @launch
192+ }
107193
108- result.getOrNull() ?.game?.let {
194+ response.data ?.game?.let {
109195 _currentGameFlow .value = ApiResponse .Success (it.toGameDetails())
110196 } ? : _currentGameFlow .update { ApiResponse .Error }
197+
198+ } catch (e: ApolloException ) {
199+ Log .e(" ScoreRepository" , " Error fetching game with id: $id : " , e)
200+ _currentGameFlow .value = ApiResponse .Error
111201 } catch (e: Exception ) {
112- Log .e(" ScoreRepository" , " Error fetching game with id: ${id} : " , e)
202+ Log .e(" ScoreRepository" , " A timeout or other error occurred for game id: $id " , e)
113203 _currentGameFlow .value = ApiResponse .Error
114204 }
115205 }
116206
117207}
118208
119209fun String.toNumberOrNull (): Number ? {
120- return when {
121- this .contains(" ." ) -> this .toFloatOrNull() // Try converting to Float if there's a decimal
122- else -> this .toIntOrNull() // Otherwise, try converting to Int
123- }
210+ return this .trim().toFloatOrNull() ? : this .trim().toIntOrNull()
124211}
212+
0 commit comments