From 06f87103d854a6d8c1cde8acf369c6404f2cc760 Mon Sep 17 00:00:00 2001 From: amjiao Date: Fri, 25 Sep 2026 10:04:39 -0400 Subject: [PATCH 1/8] Fix bug --- app/src/main/java/com/cornellappdev/score/util/GameDataUtil.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/java/com/cornellappdev/score/util/GameDataUtil.kt b/app/src/main/java/com/cornellappdev/score/util/GameDataUtil.kt index 47eafff..ac40f8c 100644 --- a/app/src/main/java/com/cornellappdev/score/util/GameDataUtil.kt +++ b/app/src/main/java/com/cornellappdev/score/util/GameDataUtil.kt @@ -97,12 +97,11 @@ fun parseResultScore(result: String?): Pair? { if (parts.size != 2) return null val scorePart = parts[1].split("-") - val secondScorePartEdge = scorePart[1].split("(") if (scorePart.size != 2) return null + val secondScorePartEdge = scorePart[1].split("(") val homeScore = scorePart[0].toIntOrNull() val oppScore = secondScorePartEdge[0].toIntOrNull() - Log.d("HIHI", oppScore.toString()) if (homeScore != null && oppScore != null) { return Pair(homeScore, oppScore) } else { From 748194a309a4766080ad853db3969fbfa04f01f8 Mon Sep 17 00:00:00 2001 From: amjiao Date: Fri, 25 Sep 2026 10:06:25 -0400 Subject: [PATCH 2/8] Modify ArticleHighlightsCard to take nullable data --- .../highlights/ArticleHighlightsCard.kt | 49 +++++++++---------- .../highlights/HighlightsCardLazyColumn.kt | 2 +- .../cornellappdev/score/model/Highlights.kt | 12 ++--- 3 files changed, 29 insertions(+), 34 deletions(-) diff --git a/app/src/main/java/com/cornellappdev/score/components/highlights/ArticleHighlightsCard.kt b/app/src/main/java/com/cornellappdev/score/components/highlights/ArticleHighlightsCard.kt index bc34227..2316c18 100644 --- a/app/src/main/java/com/cornellappdev/score/components/highlights/ArticleHighlightsCard.kt +++ b/app/src/main/java/com/cornellappdev/score/components/highlights/ArticleHighlightsCard.kt @@ -11,8 +11,6 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.foundation.text.BasicText -import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment @@ -20,21 +18,12 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.text.LinkAnnotation -import androidx.compose.ui.text.SpanStyle -import androidx.compose.ui.text.TextLinkStyles -import androidx.compose.ui.text.buildAnnotatedString -import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.text.withLink import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import coil3.compose.AsyncImage -import com.cornellappdev.score.R import com.cornellappdev.score.model.ArticleHighlightData import com.cornellappdev.score.model.Sport -import com.cornellappdev.score.theme.Style.bodySemibold import com.cornellappdev.score.theme.Style.heading2 import com.cornellappdev.score.theme.Style.labelsNormal import com.cornellappdev.score.theme.White @@ -67,13 +56,15 @@ fun ArticleHighlightCard( .padding(12.dp), verticalArrangement = Arrangement.SpaceBetween ) { - Text( - style = heading2, - color = Color.White, - text = articleHighlight.title, - maxLines = 4, - overflow = TextOverflow.Ellipsis - ) + articleHighlight.title?.let { + Text( + style = heading2, + color = Color.White, + text = it, + maxLines = 4, + overflow = TextOverflow.Ellipsis + ) + } Row( modifier = Modifier.fillMaxWidth(), @@ -86,17 +77,21 @@ fun ArticleHighlightCard( if (isWideFormat) { Text("Read at ", color = White) } - ExternalLink( - articleHighlight.articleUrl, - urlLabel = "Cornell Daily Sun", - linkColor = White + if (articleHighlight.articleUrl != null){ + ExternalLink( + articleHighlight.articleUrl, + urlLabel = "Cornell Daily Sun", + linkColor = White + ) + } + } + articleHighlight.date?.let { + Text( + color = Color.White, + style = labelsNormal, + text = it ) } - Text( - color = Color.White, - style = labelsNormal, - text = articleHighlight.date - ) } } } diff --git a/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsCardLazyColumn.kt b/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsCardLazyColumn.kt index 2a9d968..b81f003 100644 --- a/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsCardLazyColumn.kt +++ b/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsCardLazyColumn.kt @@ -53,7 +53,7 @@ fun HighlightsCardLazyColumn( query.isNotEmpty() -> { val filtered = highlightsList.filter { - it.title.contains(query, ignoreCase = true) + it.title?.contains(query, ignoreCase = true) == true } if (filtered.isEmpty()) { diff --git a/app/src/main/java/com/cornellappdev/score/model/Highlights.kt b/app/src/main/java/com/cornellappdev/score/model/Highlights.kt index a1a96b2..cdf4dd7 100644 --- a/app/src/main/java/com/cornellappdev/score/model/Highlights.kt +++ b/app/src/main/java/com/cornellappdev/score/model/Highlights.kt @@ -10,15 +10,15 @@ data class VideoHighlightData( ) data class ArticleHighlightData( - val title: String, - val imageUrl: String, - val articleUrl: String, - val date: String, - val sport: Sport + val title: String?, + val imageUrl: String?, + val articleUrl: String?, + val date: String?, + val sport: Sport? ) sealed class HighlightData { - abstract val title: String + abstract val title: String? data class Video(val data: VideoHighlightData) : HighlightData() { override val title = data.title From d061d2b469408881f36557d8a13ee0daab7fcc53 Mon Sep 17 00:00:00 2001 From: amjiao Date: Fri, 25 Sep 2026 10:06:47 -0400 Subject: [PATCH 3/8] Update models with recap fields --- app/src/main/java/com/cornellappdev/score/model/Game.kt | 9 +++++++-- .../cornellappdev/score/model/GameByIdQueryMappers.kt | 6 +++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/cornellappdev/score/model/Game.kt b/app/src/main/java/com/cornellappdev/score/model/Game.kt index ee3cb19..b38c740 100644 --- a/app/src/main/java/com/cornellappdev/score/model/Game.kt +++ b/app/src/main/java/com/cornellappdev/score/model/Game.kt @@ -68,7 +68,11 @@ data class GameDetailsGame( val time: String?, val scoreBreakdown: List?>?, val team: GameDetailsTeam?, - val boxScore: List? + val boxScore: List?, + val recapLink: String?, + val recapArticleTitle: String?, + val recapArticleImage: String?, + val recapPublishedAt: String? ) @@ -306,7 +310,8 @@ fun GameDetailsGame.toGameCardData(): DetailsCardData { homeScore = convertScores(scoreBreakdown?.getOrNull(0), sport, result ?: "").second ?: parsedScores?.first ?: 0, oppScore = convertScores(scoreBreakdown?.getOrNull(1), sport, result ?: "").second - ?: parsedScores?.second ?: 0 + ?: parsedScores?.second ?: 0, + articleData = ArticleHighlightData(title = recapArticleTitle, imageUrl = recapArticleImage, articleUrl = recapLink, date = recapPublishedAt, sport = Sport.fromDisplayName(sport)) ) } diff --git a/app/src/main/java/com/cornellappdev/score/model/GameByIdQueryMappers.kt b/app/src/main/java/com/cornellappdev/score/model/GameByIdQueryMappers.kt index 81ad01a..21803da 100644 --- a/app/src/main/java/com/cornellappdev/score/model/GameByIdQueryMappers.kt +++ b/app/src/main/java/com/cornellappdev/score/model/GameByIdQueryMappers.kt @@ -17,7 +17,11 @@ fun GameByIdQuery.Game.toGameDetails(): GameDetailsGame { time = this.time, scoreBreakdown = this.scoreBreakdown, team = this.team?.toGameDetailsTeam(), - boxScore = this.boxScore?.mapNotNull { it?.toGameDetailsBoxScore() } + boxScore = this.boxScore?.mapNotNull { it?.toGameDetailsBoxScore() }, + recapLink = this.recapLink, + recapArticleTitle = this.recapArticleTitle, + recapArticleImage = this.recapArticleImage, + recapPublishedAt = this.recapPublishedAt ) } fun GameByIdQuery.Team.toGameDetailsTeam(): GameDetailsTeam { From 3d32680220c148058d7d7f7dd92dace96fef0bf8 Mon Sep 17 00:00:00 2001 From: amjiao Date: Wed, 30 Sep 2026 02:59:34 -0400 Subject: [PATCH 4/8] Populate softball scores --- .../main/java/com/cornellappdev/score/util/GameDataUtil.kt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/src/main/java/com/cornellappdev/score/util/GameDataUtil.kt b/app/src/main/java/com/cornellappdev/score/util/GameDataUtil.kt index ac40f8c..beef8ea 100644 --- a/app/src/main/java/com/cornellappdev/score/util/GameDataUtil.kt +++ b/app/src/main/java/com/cornellappdev/score/util/GameDataUtil.kt @@ -11,6 +11,7 @@ import com.cornellappdev.score.model.TeamScore * Handles null values and non-numeric values: * - Nulls or "X" are 0 * - If the sport is baseball, only the first 9 periods counted + * - If the sport is softball, only the first 7 periods counted * - For other sports, the last item in the list is treated as the total score. * * @param scoreList the list of score strings, where each item represents a period score and the last item may be the total @@ -42,6 +43,12 @@ fun convertScores(scoreList: List?, sport: String, result: String): Pai return Pair(scoresByPeriod, totalScore) } + if (sport.lowercase() == "softball"){ + scoresByPeriod = scoresByPeriod.dropLast(2) //backend includes a column for aggregate scores before R, H, E metrics + val totalScore = scoresByPeriod.sum() + return Pair(scoresByPeriod, totalScore) + } + val totalScore = scoreList.last()?.toIntOrNull() return Pair(scoresByPeriod, totalScore) } From cdd252b028d92c91197dc8412455485cefef347f Mon Sep 17 00:00:00 2001 From: amjiao Date: Wed, 30 Sep 2026 18:08:34 -0400 Subject: [PATCH 5/8] Clean up imports --- .../com/cornellappdev/score/viewmodel/GameDetailsViewModel.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/src/main/java/com/cornellappdev/score/viewmodel/GameDetailsViewModel.kt b/app/src/main/java/com/cornellappdev/score/viewmodel/GameDetailsViewModel.kt index 1b69f30..259d600 100644 --- a/app/src/main/java/com/cornellappdev/score/viewmodel/GameDetailsViewModel.kt +++ b/app/src/main/java/com/cornellappdev/score/viewmodel/GameDetailsViewModel.kt @@ -1,13 +1,11 @@ package com.cornellappdev.score.viewmodel import androidx.lifecycle.SavedStateHandle -import androidx.navigation.toRoute import com.cornellappdev.score.model.ApiResponse import com.cornellappdev.score.model.DetailsCardData import com.cornellappdev.score.model.ScoreRepository import com.cornellappdev.score.model.map import com.cornellappdev.score.model.toGameCardData -import com.cornellappdev.score.nav.root.ScoreScreens import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject From 471bafd5dd122d403eac18f469fb139bc07bb223 Mon Sep 17 00:00:00 2001 From: amjiao Date: Wed, 30 Sep 2026 18:09:13 -0400 Subject: [PATCH 6/8] Add softball case (remove extra columns) --- .../main/java/com/cornellappdev/score/util/GameDataUtil.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/cornellappdev/score/util/GameDataUtil.kt b/app/src/main/java/com/cornellappdev/score/util/GameDataUtil.kt index beef8ea..934d39e 100644 --- a/app/src/main/java/com/cornellappdev/score/util/GameDataUtil.kt +++ b/app/src/main/java/com/cornellappdev/score/util/GameDataUtil.kt @@ -1,6 +1,5 @@ package com.cornellappdev.score.util -import android.util.Log import com.cornellappdev.score.model.GameData import com.cornellappdev.score.model.TeamBoxScore import com.cornellappdev.score.model.TeamScore @@ -43,8 +42,9 @@ fun convertScores(scoreList: List?, sport: String, result: String): Pai return Pair(scoresByPeriod, totalScore) } - if (sport.lowercase() == "softball"){ - scoresByPeriod = scoresByPeriod.dropLast(2) //backend includes a column for aggregate scores before R, H, E metrics + if (sport.lowercase() == "softball") { + scoresByPeriod = + scoresByPeriod.dropLast(2) //backend includes a column for aggregate scores before R, H, E metrics val totalScore = scoresByPeriod.sum() return Pair(scoresByPeriod, totalScore) } From 07ea78c64a9de5a340dfe0aa0756ae96aa5e6e91 Mon Sep 17 00:00:00 2001 From: amjiao Date: Wed, 30 Sep 2026 18:13:42 -0400 Subject: [PATCH 7/8] Pattern matching result string format to header This could prob go in a viewmodel but i think that overcomplicates it cause then we'd have to assign types somehow and pass that in as a parameter in a bunch of places --- .../score/screen/GameDetailsScreen.kt | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/com/cornellappdev/score/screen/GameDetailsScreen.kt b/app/src/main/java/com/cornellappdev/score/screen/GameDetailsScreen.kt index 0dc6f24..990f4ca 100644 --- a/app/src/main/java/com/cornellappdev/score/screen/GameDetailsScreen.kt +++ b/app/src/main/java/com/cornellappdev/score/screen/GameDetailsScreen.kt @@ -26,7 +26,6 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel -import com.apollographql.apollo.api.BooleanExpression import com.cornellappdev.score.R import com.cornellappdev.score.components.AlternativeScoreHeader import com.cornellappdev.score.components.BoxScore @@ -35,7 +34,6 @@ import com.cornellappdev.score.components.ErrorState import com.cornellappdev.score.components.GameDetailsLoadingScreen import com.cornellappdev.score.components.GameScoreHeader import com.cornellappdev.score.components.NavigationHeader -import com.cornellappdev.score.components.NthPlaceScoreHeader import com.cornellappdev.score.components.ScorePreview import com.cornellappdev.score.components.ScorePullToRefreshBox import com.cornellappdev.score.components.ScoringSummary @@ -120,25 +118,25 @@ fun GameDetailsContent( horizontalAlignment = Alignment.CenterHorizontally ) { - if (gameCard.result != null) { - if (gameCard.result.contains("place")) { - val place = gameCard.result.split(",")[0] - AlternativeScoreHeader(place) + //Logic to determine header type + if (!gameCard.result.isNullOrBlank() && !gameCard.result.contains("-")) { + if (!gameCard.result.any { it.isDigit() }) { //i.e. NTS, Cancelled + AlternativeScoreHeader( + resultString = gameCard.result, + modifier = Modifier.height(185.dp) + ) + } else if (gameCard.result.split(" ").size == 1) { //i.e. 3rd + AlternativeScoreHeader( + resultString = "${gameCard.result} Place", + modifier = Modifier.height(185.dp) + ) } else if (gameCard.result.contains("of")) { - //todo take the first three words of result - } else if (gameCard.title.contains("Tournament")) { - //todo: how do i extract this? - AlternativeScoreHeader("Temp") - } else if (gameCard.result.contains("-")) { - //todo jk we can prob just feed the string into the standard score header: GameScoreHeader - AlternativeScoreHeader("Temp") -// val temp = gameCard.result.split(",")[1].trim(), -// val rawScores = temp.split("-") -// val leftScore = rawScores[0] -// val rightScore = rawScores[1] + val res = gameCard.result.split(" ").take(3).joinToString(" ") + AlternativeScoreHeader(resultString = res, modifier = Modifier.height(185.dp)) } - }else { - //standard score header + //todo add case for ncaa tournament + } else { + //Standard score header GameScoreHeader( leftTeamLogo = painterResource(R.drawable.cornell_logo), rightTeamLogo = gameCard.opponentLogo, @@ -173,6 +171,8 @@ fun GameDetailsContent( ) -> if (gameCard.articleData != null) { GameDetailsContentRecap(gameCard.articleData) + } else { + Text("No recap available") } in listOf( From 4b7dc1a06e60d4340b0f0cc1f8dc13f814e2ea6c Mon Sep 17 00:00:00 2001 From: amjiao Date: Wed, 30 Sep 2026 18:14:57 -0400 Subject: [PATCH 8/8] Add recap fields as article to game type --- .../main/java/com/cornellappdev/score/model/Game.kt | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/cornellappdev/score/model/Game.kt b/app/src/main/java/com/cornellappdev/score/model/Game.kt index b38c740..9a28541 100644 --- a/app/src/main/java/com/cornellappdev/score/model/Game.kt +++ b/app/src/main/java/com/cornellappdev/score/model/Game.kt @@ -311,7 +311,18 @@ fun GameDetailsGame.toGameCardData(): DetailsCardData { ?: parsedScores?.first ?: 0, oppScore = convertScores(scoreBreakdown?.getOrNull(1), sport, result ?: "").second ?: parsedScores?.second ?: 0, - articleData = ArticleHighlightData(title = recapArticleTitle, imageUrl = recapArticleImage, articleUrl = recapLink, date = recapPublishedAt, sport = Sport.fromDisplayName(sport)) + articleData = if (recapLink == null && recapArticleTitle == null) { + null + } else { + ArticleHighlightData( + title = recapArticleTitle, + imageUrl = recapArticleImage, + articleUrl = recapLink, + date = recapPublishedAt, + sport = Sport.fromDisplayName(sport) + ) + }, + result = result ) }