From df8c255d6d834668f1cade49df6a5cc177638160 Mon Sep 17 00:00:00 2001 From: amjiao Date: Wed, 17 Sep 2025 15:31:10 -0400 Subject: [PATCH 01/11] mostly done, small bugs left --- .../score/components/ScoreBox.kt | 307 +++++++++++++----- .../com/cornellappdev/score/model/Game.kt | 24 ++ .../cornellappdev/score/theme/TextStyle.kt | 6 + .../score/util/TestingConstants.kt | 14 + 4 files changed, 273 insertions(+), 78 deletions(-) diff --git a/app/src/main/java/com/cornellappdev/score/components/ScoreBox.kt b/app/src/main/java/com/cornellappdev/score/components/ScoreBox.kt index 088e0f6..12c2249 100644 --- a/app/src/main/java/com/cornellappdev/score/components/ScoreBox.kt +++ b/app/src/main/java/com/cornellappdev/score/components/ScoreBox.kt @@ -2,19 +2,23 @@ package com.cornellappdev.score.components import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.background -import androidx.compose.foundation.border import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.IntrinsicSize import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +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.material3.HorizontalDivider +import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight @@ -24,132 +28,280 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.cornellappdev.score.model.GameData import com.cornellappdev.score.model.TeamScore +import com.cornellappdev.score.model.mapToPeriodScores import com.cornellappdev.score.theme.CrimsonPrimary import com.cornellappdev.score.theme.GrayMedium import com.cornellappdev.score.theme.GrayPrimary -import com.cornellappdev.score.theme.Style.bodyNormal -import com.cornellappdev.score.theme.Style.labelsNormal +import com.cornellappdev.score.theme.Style.metricNormal +import com.cornellappdev.score.theme.Style.metricSmallNormal import com.cornellappdev.score.theme.saturatedGreen import com.cornellappdev.score.util.emptyGameData import com.cornellappdev.score.util.gameData import com.cornellappdev.score.util.longGameData import com.cornellappdev.score.util.mediumGameData +import com.cornellappdev.score.util.shortGameData @Composable -fun BoxScore(gameData: GameData) { +fun BoxScore( + gameData: GameData, + modifier: Modifier = Modifier +) { val maxPeriods = maxOf( gameData.teamScores.first.scoresByPeriod.size, gameData.teamScores.second.scoresByPeriod.size ) - val rowTextStyle = if (maxPeriods > 4) labelsNormal else bodyNormal + val rowTextStyle = if (maxPeriods > 4) metricSmallNormal else metricNormal + + Surface( + modifier = modifier + .fillMaxWidth(), + shape = RoundedCornerShape(8.dp), + border = (BorderStroke(width = 1.dp, color = CrimsonPrimary)), + shadowElevation = 8.dp, + color = Color.White + ) { + Row( + modifier = Modifier + .height(IntrinsicSize.Max) + .fillMaxWidth() + ) { + TeamNameColumn( + gameData.teamScores.first.team.name, + gameData.teamScores.second.team.name, + rowTextStyle + ) + CompleteTableData( + gameData = gameData, + rowTextStyle = rowTextStyle + ) + } + } +} + +@Composable +private fun TeamNameColumn( + teamOneName: String, + teamTwoName: String, + rowTextStyle: TextStyle, + modifier: Modifier = Modifier +) { Column( - modifier = Modifier - .fillMaxWidth() - .clip(shape = RoundedCornerShape(8.dp)) - .background(color = Color.White, shape = RoundedCornerShape(8.dp)) - .border(BorderStroke(width = 1.dp, color = CrimsonPrimary)) + modifier = modifier.width(60.dp) + //.width(IntrinsicSize.Max) ) { Row( modifier = Modifier .fillMaxWidth() .background(color = CrimsonPrimary) - .padding(top = 6.dp, bottom = 4.dp, end = 8.dp), + .weight(1F) + .padding(top = 6.dp, bottom = 4.dp) + ) {} + Row( + modifier = Modifier + .fillMaxWidth() + .weight(1F) + .padding(top = 8.dp, bottom = 8.dp) + ) { + Text( + text = teamOneName, + style = rowTextStyle, + color = GrayPrimary, + modifier = Modifier + .weight(1f, fill = true) + .padding(10.dp), + textAlign = TextAlign.Left, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + } + HorizontalDivider(thickness = 1.dp, color = CrimsonPrimary) + Row( + modifier = Modifier + .fillMaxWidth() + .weight(1f) + .padding(top = 8.dp, bottom = 8.dp) + ) { + Text( + text = teamTwoName, + style = rowTextStyle, + color = GrayPrimary, + modifier = Modifier + .weight(1f, fill = true) + .padding(10.dp), + textAlign = TextAlign.Left, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + } + } +} + +@Composable +private fun TableDataColumn( + header: Int, + team1Score: String, + team2Score: String, + rowTextStyle: TextStyle, + modifier: Modifier = Modifier +) { + Column( + modifier = modifier + .fillMaxHeight() + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .background(color = CrimsonPrimary) + .weight(1f), + horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically ) { Text( - text = "", - modifier = Modifier.weight(1f), + text = header.toString(), color = Color.White, + style = rowTextStyle, textAlign = TextAlign.Center ) - repeat(maxPeriods) { period -> - Text( - text = "${period + 1}", - modifier = Modifier.weight(1f), - color = Color.White, - style = rowTextStyle, - textAlign = TextAlign.Center - ) - } + } + Row( + modifier = Modifier + .fillMaxWidth() + .weight(1f), + horizontalArrangement = Arrangement.Center, + verticalAlignment = Alignment.CenterVertically + ) { Text( - text = "Total", - modifier = Modifier.weight(1f), + text = team1Score, style = rowTextStyle, - color = Color.White, textAlign = TextAlign.Center ) } - TeamScoreRow( - teamScore = gameData.teamScores.first, - totalTextColor = saturatedGreen, - maxPeriods, - rowTextStyle - ) HorizontalDivider(thickness = 1.dp, color = CrimsonPrimary) + Row( + modifier = Modifier + .fillMaxWidth() + .weight(1f), + horizontalArrangement = Arrangement.Center, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = team2Score, + style = rowTextStyle, + textAlign = TextAlign.Center + ) + } + } +} - TeamScoreRow( - teamScore = gameData.teamScores.second, - totalTextColor = GrayMedium, - maxPeriods, - rowTextStyle - ) +@Composable +private fun CompleteTableData( + gameData: GameData, + rowTextStyle: TextStyle, + modifier: Modifier = Modifier +) { + Row( + modifier = modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween + ) { + val periodScores = mapToPeriodScores(gameData) + if (periodScores.isNotEmpty()) { + mapToPeriodScores(gameData).map { periodScore -> + TableDataColumn( + header = periodScore.header, + team1Score = periodScore.teamOneScore, + team2Score = periodScore.teamTwoScore, + rowTextStyle = rowTextStyle, + modifier = Modifier.weight(1f) + ) + } + } else { + for (i in 1..4) { + TableDataColumn( + header = i, + team1Score = "-", + team2Score = "-", + rowTextStyle = rowTextStyle, + modifier = Modifier.weight(1f) + ) + } + } + + TotalsColumn( + teamOneScores = gameData.teamScores.first, + teamTwoScores = gameData.teamScores.second, + modifier = Modifier.width(IntrinsicSize.Min), + //.weight(1f), + rowTextStyle = rowTextStyle + ) } } @Composable -fun TeamScoreRow( +private fun TotalScoreCell( teamScore: TeamScore, totalTextColor: Color, - maxPeriods: Int, - rowTextStyle: TextStyle + rowTextStyle: TextStyle, + modifier: Modifier = Modifier ) { val showEmpty = teamScore.scoresByPeriod.isEmpty() - Row( - modifier = Modifier - .fillMaxWidth() - .padding(vertical = 8.dp, horizontal = 10.dp), - horizontalArrangement = Arrangement.SpaceBetween, + modifier = modifier + .fillMaxSize() + .padding(top = 8.dp, bottom = 8.dp, end = 8.dp), + horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically ) { Text( - text = teamScore.team.name, + text = if (showEmpty) "-" else teamScore.totalScore.toString(), style = rowTextStyle, - color = GrayPrimary, - modifier = Modifier.weight(1f), - textAlign = TextAlign.Center, - maxLines = 1, - overflow = TextOverflow.Ellipsis + color = if (showEmpty) Color.Gray else totalTextColor, + fontWeight = if (showEmpty) FontWeight.Normal else FontWeight.Bold, + textAlign = TextAlign.Center ) + } +} - teamScore.scoresByPeriod.forEach { score -> - Text( - text = if (showEmpty) "-" else score.toString(), - modifier = Modifier.weight(1f), - style = rowTextStyle, - color = GrayPrimary, - textAlign = TextAlign.Center - ) - } - - repeat(maxPeriods - teamScore.scoresByPeriod.size) { +@Composable +private fun TotalsColumn( + teamOneScores: TeamScore, + teamTwoScores: TeamScore, + rowTextStyle: TextStyle, + modifier: Modifier = Modifier +) { + Column( + modifier = modifier + .fillMaxSize() + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .background(color = CrimsonPrimary) + .padding(end = 8.dp) + .weight(1f), + horizontalArrangement = Arrangement.Center, + verticalAlignment = Alignment.CenterVertically + ) { Text( - text = "-", - modifier = Modifier.weight(1f), + text = "Total", + color = Color.White, style = rowTextStyle, - color = GrayPrimary, textAlign = TextAlign.Center ) } - Text( - text = if (showEmpty) "-" else teamScore.totalScore.toString(), - modifier = Modifier.weight(1f), - style = rowTextStyle, - color = if (showEmpty) Color.Gray else totalTextColor, - fontWeight = if (showEmpty) FontWeight.Normal else FontWeight.Bold, - textAlign = TextAlign.Center + TotalScoreCell( + teamScore = teamOneScores, + totalTextColor = saturatedGreen, + rowTextStyle = rowTextStyle, + modifier = Modifier.weight(1f) + ) + HorizontalDivider(thickness = 1.dp, color = CrimsonPrimary) + TotalScoreCell( + teamScore = teamTwoScores, + totalTextColor = GrayMedium, + rowTextStyle = rowTextStyle, + modifier = Modifier.weight(1f) ) } } @@ -175,13 +327,12 @@ private fun PreviewBoxScoreForMedGame() = ScorePreview { @Preview @Composable -private fun PreviewBoxScoreEmpty() = ScorePreview { - BoxScore(gameData = emptyGameData()) +private fun PreviewBoxScoreForShortGame() = ScorePreview { + BoxScore(shortGameData) } - @Preview @Composable -private fun PreviewTeamScoreRow() = ScorePreview { - TeamScoreRow(gameData.teamScores.first, GrayMedium, 4, bodyNormal) +private fun PreviewBoxScoreEmpty() = ScorePreview { + BoxScore(gameData = emptyGameData()) } \ No newline at end of file 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 18ed1a2..8d6290a 100644 --- a/app/src/main/java/com/cornellappdev/score/model/Game.kt +++ b/app/src/main/java/com/cornellappdev/score/model/Game.kt @@ -1,5 +1,6 @@ package com.cornellappdev.score.model +import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import com.cornellappdev.score.R import com.cornellappdev.score.util.convertScores @@ -130,6 +131,12 @@ data class DetailsCardData( ) // Scoring information for a specific team, used in the box score +data class ScoresByPeriod( + val header: Int, + val teamOneScore: String, + val teamTwoScore: String +) + data class TeamScore( val team: TeamBoxScore, val scoresByPeriod: List, @@ -291,4 +298,21 @@ fun List.toScoreEvents(teamLogo: String): List description = boxScore.description ) } +} + +fun mapToPeriodScores(gameData: GameData): List{ + val teamOneScores = gameData.teamScores.first.scoresByPeriod + val teamTwoScores = gameData.teamScores.second.scoresByPeriod + + val maxPeriods = maxOf(teamOneScores.size, teamTwoScores.size) + + return (0 until maxPeriods).map { i -> + ScoresByPeriod( + header = i + 1, + teamOneScore = teamOneScores.getOrNull(i)?.toString() ?: "-", + teamTwoScore = teamTwoScores.getOrNull(i)?.toString() ?: "-" + + ) + + } } \ No newline at end of file diff --git a/app/src/main/java/com/cornellappdev/score/theme/TextStyle.kt b/app/src/main/java/com/cornellappdev/score/theme/TextStyle.kt index a09e045..c2fd46e 100644 --- a/app/src/main/java/com/cornellappdev/score/theme/TextStyle.kt +++ b/app/src/main/java/com/cornellappdev/score/theme/TextStyle.kt @@ -196,6 +196,12 @@ object Style { fontWeight = FontWeight(500) ) + val metricSmallNormal = TextStyle( + fontSize = 14.sp, + fontFamily = poppinsFamily, + fontWeight = FontWeight(400) + ) + val metricNormal = TextStyle( fontSize = 18.sp, fontFamily = poppinsFamily, diff --git a/app/src/main/java/com/cornellappdev/score/util/TestingConstants.kt b/app/src/main/java/com/cornellappdev/score/util/TestingConstants.kt index 382ffc6..9016f87 100644 --- a/app/src/main/java/com/cornellappdev/score/util/TestingConstants.kt +++ b/app/src/main/java/com/cornellappdev/score/util/TestingConstants.kt @@ -68,6 +68,18 @@ val teamScore2 = TeamScore( totalScore = 23 ) +val shortGameTeamScore1 = TeamScore( + team = team1, + scoresByPeriod = listOf(13, 14), + totalScore = 27 +) + +val shortGameTeamScore2 = TeamScore( + team = team2, + scoresByPeriod = listOf(7, 7), + totalScore = 14 +) + val mediumGameTeamScore1 = TeamScore( team = team1, scoresByPeriod = listOf(13, 14, 6, 14, 13, 2), @@ -91,6 +103,8 @@ val longGameTeamScore2 = TeamScore( ) val gameData = GameData(teamScores = Pair(teamScore1, teamScore2)) +val shortGameData = GameData(teamScores = shortGameTeamScore1 to shortGameTeamScore2) + val mediumGameData = GameData(teamScores = mediumGameTeamScore1 to mediumGameTeamScore2) val longGameData = GameData(teamScores = longGameTeamScore1 to longGameTeamScore2) From b358593fef7a17ba7c419177d6b97d57a95f2d5b Mon Sep 17 00:00:00 2001 From: amjiao Date: Wed, 17 Sep 2025 17:38:00 -0400 Subject: [PATCH 02/11] Fixed lacrosse icon --- app/src/main/java/com/cornellappdev/score/model/Sport.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/cornellappdev/score/model/Sport.kt b/app/src/main/java/com/cornellappdev/score/model/Sport.kt index 5e8fd07..bcf68cb 100644 --- a/app/src/main/java/com/cornellappdev/score/model/Sport.kt +++ b/app/src/main/java/com/cornellappdev/score/model/Sport.kt @@ -87,8 +87,8 @@ enum class Sport( LACROSSE( displayName = "Lacrosse", gender = GenderDivision.ALL, - emptyIcon = R.drawable.ic_squash, - filledIcon = R.drawable.ic_squash_filled + emptyIcon = R.drawable.ic_lacrosse, + filledIcon = R.drawable.ic_lacrosse_filled ), ROWING_HEAVYWEIGHT( displayName = "Heavyweight Rowing", From 9e9a2fbaeb10792cd0d75df6a852d53203b0c2ed Mon Sep 17 00:00:00 2001 From: amjiao Date: Sun, 21 Sep 2025 00:36:51 -0400 Subject: [PATCH 03/11] Mostly working, some best practice concerns - static height in surface (to make the lazy column work) - weight(1f) in CompleteTableData for the data columns and the TotalsColumn: need equal spacing but issues when there's not enough room (i.e. 8+ data columns) and "Totals" wraps into two lines --- .../score/components/ScoreBox.kt | 157 +++++++++++++----- .../score/util/TestingConstants.kt | 13 ++ 2 files changed, 130 insertions(+), 40 deletions(-) diff --git a/app/src/main/java/com/cornellappdev/score/components/ScoreBox.kt b/app/src/main/java/com/cornellappdev/score/components/ScoreBox.kt index 12c2249..47f8ebc 100644 --- a/app/src/main/java/com/cornellappdev/score/components/ScoreBox.kt +++ b/app/src/main/java/com/cornellappdev/score/components/ScoreBox.kt @@ -3,16 +3,21 @@ package com.cornellappdev.score.components import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.IntrinsicSize import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.widthIn +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.ButtonGroupDefaults.HorizontalArrangement import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Surface import androidx.compose.material3.Text @@ -36,11 +41,14 @@ import com.cornellappdev.score.theme.Style.metricNormal import com.cornellappdev.score.theme.Style.metricSmallNormal import com.cornellappdev.score.theme.saturatedGreen import com.cornellappdev.score.util.emptyGameData +import com.cornellappdev.score.util.extraLongGameData import com.cornellappdev.score.util.gameData import com.cornellappdev.score.util.longGameData import com.cornellappdev.score.util.mediumGameData import com.cornellappdev.score.util.shortGameData +private val HEADER_HEIGHT = 35.dp + @Composable fun BoxScore( gameData: GameData, @@ -54,6 +62,8 @@ fun BoxScore( Surface( modifier = modifier + //.height(IntrinsicSize.Min) + .height(160.dp) .fillMaxWidth(), shape = RoundedCornerShape(8.dp), border = (BorderStroke(width = 1.dp, color = CrimsonPrimary)), @@ -62,18 +72,26 @@ fun BoxScore( ) { Row( modifier = Modifier - .height(IntrinsicSize.Max) .fillMaxWidth() ) { TeamNameColumn( gameData.teamScores.first.team.name, gameData.teamScores.second.team.name, - rowTextStyle - ) - CompleteTableData( - gameData = gameData, - rowTextStyle = rowTextStyle + rowTextStyle, + maxPeriods ) + if (maxPeriods > 10){ + CompleteLazyTableData( + gameData = gameData, + rowTextStyle = rowTextStyle + ) + }else{ + CompleteTableData( + gameData = gameData, + rowTextStyle = rowTextStyle, + maxPeriods = maxPeriods + ) + } } } } @@ -83,24 +101,30 @@ private fun TeamNameColumn( teamOneName: String, teamTwoName: String, rowTextStyle: TextStyle, + maxPeriods: Int, modifier: Modifier = Modifier ) { Column( - modifier = modifier.width(60.dp) - //.width(IntrinsicSize.Max) + modifier = if (maxPeriods > 4) { + modifier.widthIn(max = 70.dp) + } else { + modifier.width(IntrinsicSize.Max) + } ) { Row( modifier = Modifier .fillMaxWidth() .background(color = CrimsonPrimary) - .weight(1F) - .padding(top = 6.dp, bottom = 4.dp) + .height(HEADER_HEIGHT) + .padding(top = 6.dp, bottom = 4.dp), ) {} Row( modifier = Modifier .fillMaxWidth() - .weight(1F) - .padding(top = 8.dp, bottom = 8.dp) + .weight(1f) + .padding(top = 8.dp, bottom = 8.dp), + horizontalArrangement = Arrangement.Start, + verticalAlignment = Alignment.CenterVertically ) { Text( text = teamOneName, @@ -119,7 +143,9 @@ private fun TeamNameColumn( modifier = Modifier .fillMaxWidth() .weight(1f) - .padding(top = 8.dp, bottom = 8.dp) + .padding(top = 8.dp, bottom = 8.dp), + horizontalArrangement = Arrangement.Start, + verticalAlignment = Alignment.CenterVertically ) { Text( text = teamTwoName, @@ -139,20 +165,19 @@ private fun TeamNameColumn( @Composable private fun TableDataColumn( header: Int, - team1Score: String, - team2Score: String, + teamOneScore: String, + teamTwoScore: String, rowTextStyle: TextStyle, modifier: Modifier = Modifier ) { Column( - modifier = modifier - .fillMaxHeight() + modifier = modifier.fillMaxWidth() ) { Row( modifier = Modifier .fillMaxWidth() .background(color = CrimsonPrimary) - .weight(1f), + .height(HEADER_HEIGHT), horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically ) { @@ -171,7 +196,7 @@ private fun TableDataColumn( verticalAlignment = Alignment.CenterVertically ) { Text( - text = team1Score, + text = teamOneScore, style = rowTextStyle, textAlign = TextAlign.Center ) @@ -185,7 +210,7 @@ private fun TableDataColumn( verticalAlignment = Alignment.CenterVertically ) { Text( - text = team2Score, + text = teamTwoScore, style = rowTextStyle, textAlign = TextAlign.Center ) @@ -193,24 +218,67 @@ private fun TableDataColumn( } } +@Composable +private fun CompleteLazyTableData( + gameData: GameData, + rowTextStyle: TextStyle, + modifier: Modifier = Modifier +) { + //todo: lazy row for maxPeriods > 10 + val periodScores = mapToPeriodScores(gameData) + + if (periodScores.isNotEmpty()) { + Row{ +// Box( +// modifier = Modifier//.weight(1f) +// .fillMaxWidth() +// ){ + LazyRow( + modifier = Modifier.weight(1f), + //horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + items(periodScores) { periodScore -> + TableDataColumn( + header = periodScore.header, + teamOneScore = periodScore.teamOneScore, + teamTwoScore = periodScore.teamTwoScore, + rowTextStyle = rowTextStyle, + modifier = Modifier.width(35.dp) + ) + } + } + //} + TotalsColumn( + teamOneScores = gameData.teamScores.first, + teamTwoScores = gameData.teamScores.second, +// modifier = Modifier +// .width(IntrinsicSize.Max), + //.weight(1f), + rowTextStyle = rowTextStyle + ) + } + } + +} + @Composable private fun CompleteTableData( gameData: GameData, rowTextStyle: TextStyle, + maxPeriods: Int, modifier: Modifier = Modifier ) { - Row( - modifier = modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceBetween - ) { - val periodScores = mapToPeriodScores(gameData) + val periodScores = mapToPeriodScores(gameData) + Row( + horizontalArrangement = Arrangement.SpaceEvenly + ){ if (periodScores.isNotEmpty()) { mapToPeriodScores(gameData).map { periodScore -> TableDataColumn( header = periodScore.header, - team1Score = periodScore.teamOneScore, - team2Score = periodScore.teamTwoScore, + teamOneScore = periodScore.teamOneScore, + teamTwoScore = periodScore.teamTwoScore, rowTextStyle = rowTextStyle, modifier = Modifier.weight(1f) ) @@ -219,22 +287,23 @@ private fun CompleteTableData( for (i in 1..4) { TableDataColumn( header = i, - team1Score = "-", - team2Score = "-", + teamOneScore = "-", + teamTwoScore = "-", rowTextStyle = rowTextStyle, modifier = Modifier.weight(1f) ) } } - TotalsColumn( - teamOneScores = gameData.teamScores.first, - teamTwoScores = gameData.teamScores.second, - modifier = Modifier.width(IntrinsicSize.Min), - //.weight(1f), - rowTextStyle = rowTextStyle - ) + teamOneScores = gameData.teamScores.first, + teamTwoScores = gameData.teamScores.second, + modifier = Modifier + //.width(IntrinsicSize.Min) + .weight(1f, fill = true), + rowTextStyle = rowTextStyle + ) } + } @Composable @@ -247,7 +316,7 @@ private fun TotalScoreCell( val showEmpty = teamScore.scoresByPeriod.isEmpty() Row( modifier = modifier - .fillMaxSize() + .fillMaxWidth() .padding(top = 8.dp, bottom = 8.dp, end = 8.dp), horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically @@ -271,14 +340,16 @@ private fun TotalsColumn( ) { Column( modifier = modifier - .fillMaxSize() + //.wrapContentHeight() + .width(IntrinsicSize.Min) + //.widthIn(min = 50.dp) ) { Row( modifier = Modifier .fillMaxWidth() .background(color = CrimsonPrimary) .padding(end = 8.dp) - .weight(1f), + .height(HEADER_HEIGHT), horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically ) { @@ -331,6 +402,12 @@ private fun PreviewBoxScoreForShortGame() = ScorePreview { BoxScore(shortGameData) } +@Preview +@Composable +private fun PreviewBoxScoreExtraLongGame() = ScorePreview { + BoxScore(gameData = extraLongGameData) +} + @Preview @Composable private fun PreviewBoxScoreEmpty() = ScorePreview { diff --git a/app/src/main/java/com/cornellappdev/score/util/TestingConstants.kt b/app/src/main/java/com/cornellappdev/score/util/TestingConstants.kt index 9016f87..80dd202 100644 --- a/app/src/main/java/com/cornellappdev/score/util/TestingConstants.kt +++ b/app/src/main/java/com/cornellappdev/score/util/TestingConstants.kt @@ -100,7 +100,18 @@ val longGameTeamScore2 = TeamScore( team = team1, scoresByPeriod = listOf(7, 7, 9, 0, 7, 7, 9, 0, 7, 2), totalScore = 47 + +val extraLongGameTeamScore1 = TeamScore( + team = team1, + scoresByPeriod = listOf(13, 14, 6, 14, 13, 2, 4, 6, 2, 2, 3, 4), + totalScore = 54 +) +val extraLongGameTeamScore2 = TeamScore( + team = team1, + scoresByPeriod = listOf(7, 7, 9, 0, 7, 7, 9, 0, 7, 2, 1, 1), + totalScore = 49 ) + val gameData = GameData(teamScores = Pair(teamScore1, teamScore2)) val shortGameData = GameData(teamScores = shortGameTeamScore1 to shortGameTeamScore2) @@ -109,6 +120,8 @@ val mediumGameData = GameData(teamScores = mediumGameTeamScore1 to mediumGameTea val longGameData = GameData(teamScores = longGameTeamScore1 to longGameTeamScore2) +val extraLongGameData = GameData(teamScores = extraLongGameTeamScore1 to extraLongGameTeamScore2) + val team3 = TeamGameSummary( name = "Cornell", "https://cornellbigred.com/images/logos/penn_200x200.png?width=80&height=80&mode=max" From 8787e330eddd649f72d43e7d31c46790d2bad1e0 Mon Sep 17 00:00:00 2001 From: amjiao Date: Sun, 21 Sep 2025 18:30:10 -0400 Subject: [PATCH 04/11] Addressed all cases, cleaned code --- .../score/components/ScoreBox.kt | 79 +++++++++---------- .../score/util/TestingConstants.kt | 2 + 2 files changed, 39 insertions(+), 42 deletions(-) diff --git a/app/src/main/java/com/cornellappdev/score/components/ScoreBox.kt b/app/src/main/java/com/cornellappdev/score/components/ScoreBox.kt index 47f8ebc..f0ab18a 100644 --- a/app/src/main/java/com/cornellappdev/score/components/ScoreBox.kt +++ b/app/src/main/java/com/cornellappdev/score/components/ScoreBox.kt @@ -3,21 +3,17 @@ package com.cornellappdev.score.components import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.IntrinsicSize import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.widthIn -import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.ButtonGroupDefaults.HorizontalArrangement import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Surface import androidx.compose.material3.Text @@ -58,11 +54,16 @@ fun BoxScore( gameData.teamScores.first.scoresByPeriod.size, gameData.teamScores.second.scoresByPeriod.size ) - val rowTextStyle = if (maxPeriods > 4) metricSmallNormal else metricNormal + + val rowTextStyle = if (maxPeriods > 4) { + metricSmallNormal + } else { + metricNormal + } Surface( modifier = modifier - //.height(IntrinsicSize.Min) + //set height required for CompleteLazyTableData case .height(160.dp) .fillMaxWidth(), shape = RoundedCornerShape(8.dp), @@ -80,12 +81,12 @@ fun BoxScore( rowTextStyle, maxPeriods ) - if (maxPeriods > 10){ + if (maxPeriods > 10) { CompleteLazyTableData( gameData = gameData, rowTextStyle = rowTextStyle ) - }else{ + } else { CompleteTableData( gameData = gameData, rowTextStyle = rowTextStyle, @@ -224,41 +225,32 @@ private fun CompleteLazyTableData( rowTextStyle: TextStyle, modifier: Modifier = Modifier ) { - //todo: lazy row for maxPeriods > 10 val periodScores = mapToPeriodScores(gameData) if (periodScores.isNotEmpty()) { - Row{ -// Box( -// modifier = Modifier//.weight(1f) -// .fillMaxWidth() -// ){ - LazyRow( - modifier = Modifier.weight(1f), - //horizontalArrangement = Arrangement.spacedBy(8.dp) - ) { - items(periodScores) { periodScore -> - TableDataColumn( - header = periodScore.header, - teamOneScore = periodScore.teamOneScore, - teamTwoScore = periodScore.teamTwoScore, - rowTextStyle = rowTextStyle, - modifier = Modifier.width(35.dp) - ) - } + Row( + modifier = modifier + ) { + LazyRow( + modifier = Modifier.weight(1f) + ) { + items(periodScores) { periodScore -> + TableDataColumn( + header = periodScore.header, + teamOneScore = periodScore.teamOneScore, + teamTwoScore = periodScore.teamTwoScore, + rowTextStyle = rowTextStyle, + modifier = Modifier.width(35.dp) + ) } - //} + } TotalsColumn( teamOneScores = gameData.teamScores.first, teamTwoScores = gameData.teamScores.second, -// modifier = Modifier -// .width(IntrinsicSize.Max), - //.weight(1f), rowTextStyle = rowTextStyle ) } } - } @Composable @@ -271,8 +263,9 @@ private fun CompleteTableData( val periodScores = mapToPeriodScores(gameData) Row( + modifier = modifier, horizontalArrangement = Arrangement.SpaceEvenly - ){ + ) { if (periodScores.isNotEmpty()) { mapToPeriodScores(gameData).map { periodScore -> TableDataColumn( @@ -295,13 +288,17 @@ private fun CompleteTableData( } } TotalsColumn( - teamOneScores = gameData.teamScores.first, - teamTwoScores = gameData.teamScores.second, - modifier = Modifier - //.width(IntrinsicSize.Min) - .weight(1f, fill = true), - rowTextStyle = rowTextStyle - ) + teamOneScores = gameData.teamScores.first, + teamTwoScores = gameData.teamScores.second, + //if maxPeriods > 8, "Totals" header will wrap to two lines. In this case, don't weight so that space is allocated to TotalsColumn first + //otherwise, TotalsColumn will fit without wrapping and can be allocated equal width as the data columns + modifier = if (maxPeriods < 8) { + Modifier.weight(1f, fill = true) + } else { + Modifier + }, + rowTextStyle = rowTextStyle + ) } } @@ -340,9 +337,7 @@ private fun TotalsColumn( ) { Column( modifier = modifier - //.wrapContentHeight() .width(IntrinsicSize.Min) - //.widthIn(min = 50.dp) ) { Row( modifier = Modifier diff --git a/app/src/main/java/com/cornellappdev/score/util/TestingConstants.kt b/app/src/main/java/com/cornellappdev/score/util/TestingConstants.kt index 80dd202..9f6fcc2 100644 --- a/app/src/main/java/com/cornellappdev/score/util/TestingConstants.kt +++ b/app/src/main/java/com/cornellappdev/score/util/TestingConstants.kt @@ -100,12 +100,14 @@ val longGameTeamScore2 = TeamScore( team = team1, scoresByPeriod = listOf(7, 7, 9, 0, 7, 7, 9, 0, 7, 2), totalScore = 47 +) val extraLongGameTeamScore1 = TeamScore( team = team1, scoresByPeriod = listOf(13, 14, 6, 14, 13, 2, 4, 6, 2, 2, 3, 4), totalScore = 54 ) + val extraLongGameTeamScore2 = TeamScore( team = team1, scoresByPeriod = listOf(7, 7, 9, 0, 7, 7, 9, 0, 7, 2, 1, 1), From 3583d9a1abe9648146fa94e498c722a2b9b08971 Mon Sep 17 00:00:00 2001 From: amjiao Date: Sun, 21 Sep 2025 19:07:25 -0400 Subject: [PATCH 05/11] Added documentation, fixed total scores color logic --- .../java/com/cornellappdev/score/components/ScoreBox.kt | 9 +++++++-- app/src/main/java/com/cornellappdev/score/model/Game.kt | 3 ++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/cornellappdev/score/components/ScoreBox.kt b/app/src/main/java/com/cornellappdev/score/components/ScoreBox.kt index f0ab18a..10ab76a 100644 --- a/app/src/main/java/com/cornellappdev/score/components/ScoreBox.kt +++ b/app/src/main/java/com/cornellappdev/score/components/ScoreBox.kt @@ -107,8 +107,10 @@ private fun TeamNameColumn( ) { Column( modifier = if (maxPeriods > 4) { + //set to approximation of minimum width for "Cornell" modifier.widthIn(max = 70.dp) } else { + //can take up as much space as is available modifier.width(IntrinsicSize.Max) } ) { @@ -356,16 +358,19 @@ private fun TotalsColumn( ) } + val totalOne = teamOneScores.totalScore + val totalTwo = teamTwoScores.totalScore + TotalScoreCell( teamScore = teamOneScores, - totalTextColor = saturatedGreen, + totalTextColor = if (totalOne > totalTwo){saturatedGreen}else{GrayMedium}, rowTextStyle = rowTextStyle, modifier = Modifier.weight(1f) ) HorizontalDivider(thickness = 1.dp, color = CrimsonPrimary) TotalScoreCell( teamScore = teamTwoScores, - totalTextColor = GrayMedium, + totalTextColor = if (totalTwo > totalOne){saturatedGreen}else{GrayMedium}, rowTextStyle = rowTextStyle, modifier = Modifier.weight(1f) ) 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 8d6290a..d099ed6 100644 --- a/app/src/main/java/com/cornellappdev/score/model/Game.kt +++ b/app/src/main/java/com/cornellappdev/score/model/Game.kt @@ -130,13 +130,14 @@ data class DetailsCardData( val oppScore: Int ) -// Scoring information for a specific team, used in the box score +// Scoring information by round of a game, used in the box score data class ScoresByPeriod( val header: Int, val teamOneScore: String, val teamTwoScore: String ) +// Scoring information for a specific team, used in the box score data class TeamScore( val team: TeamBoxScore, val scoresByPeriod: List, From b4f5b17c27fd8780a1bcfcc08a6db1cf662a42b6 Mon Sep 17 00:00:00 2001 From: amjiao Date: Sun, 21 Sep 2025 19:07:43 -0400 Subject: [PATCH 06/11] Update ScoreBox tests --- .../com/cornellappdev/score/util/TestingConstants.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/cornellappdev/score/util/TestingConstants.kt b/app/src/main/java/com/cornellappdev/score/util/TestingConstants.kt index 9f6fcc2..64026a9 100644 --- a/app/src/main/java/com/cornellappdev/score/util/TestingConstants.kt +++ b/app/src/main/java/com/cornellappdev/score/util/TestingConstants.kt @@ -81,15 +81,15 @@ val shortGameTeamScore2 = TeamScore( ) val mediumGameTeamScore1 = TeamScore( - team = team1, - scoresByPeriod = listOf(13, 14, 6, 14, 13, 2), - totalScore = 62 -) -val mediumGameTeamScore2 = TeamScore( team = team1, scoresByPeriod = listOf(7, 7, 9, 0, 7, 7), totalScore = 37 ) +val mediumGameTeamScore2 = TeamScore( + team = team2, + scoresByPeriod = listOf(13, 14, 6, 14, 13, 2), + totalScore = 62 +) val longGameTeamScore1 = TeamScore( team = team1, From b6123154220f5e540827e2e4f178c4df954f6fae Mon Sep 17 00:00:00 2001 From: amjiao Date: Sun, 21 Sep 2025 19:18:49 -0400 Subject: [PATCH 07/11] Clean code --- .../com/cornellappdev/score/components/ScoreBox.kt | 12 ++++++++++-- .../main/java/com/cornellappdev/score/model/Game.kt | 3 +-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/cornellappdev/score/components/ScoreBox.kt b/app/src/main/java/com/cornellappdev/score/components/ScoreBox.kt index 10ab76a..fdd3e11 100644 --- a/app/src/main/java/com/cornellappdev/score/components/ScoreBox.kt +++ b/app/src/main/java/com/cornellappdev/score/components/ScoreBox.kt @@ -363,14 +363,22 @@ private fun TotalsColumn( TotalScoreCell( teamScore = teamOneScores, - totalTextColor = if (totalOne > totalTwo){saturatedGreen}else{GrayMedium}, + totalTextColor = if (totalOne > totalTwo) { + saturatedGreen + } else { + GrayMedium + }, rowTextStyle = rowTextStyle, modifier = Modifier.weight(1f) ) HorizontalDivider(thickness = 1.dp, color = CrimsonPrimary) TotalScoreCell( teamScore = teamTwoScores, - totalTextColor = if (totalTwo > totalOne){saturatedGreen}else{GrayMedium}, + totalTextColor = if (totalTwo > totalOne) { + saturatedGreen + } else { + GrayMedium + }, rowTextStyle = rowTextStyle, modifier = Modifier.weight(1f) ) 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 d099ed6..6ae6647 100644 --- a/app/src/main/java/com/cornellappdev/score/model/Game.kt +++ b/app/src/main/java/com/cornellappdev/score/model/Game.kt @@ -1,6 +1,5 @@ package com.cornellappdev.score.model -import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import com.cornellappdev.score.R import com.cornellappdev.score.util.convertScores @@ -301,7 +300,7 @@ fun List.toScoreEvents(teamLogo: String): List } } -fun mapToPeriodScores(gameData: GameData): List{ +fun mapToPeriodScores(gameData: GameData): List { val teamOneScores = gameData.teamScores.first.scoresByPeriod val teamTwoScores = gameData.teamScores.second.scoresByPeriod From a5255aed1692dbf4c0c5a9417be4ecc97ea8fe1d Mon Sep 17 00:00:00 2001 From: amjiao Date: Mon, 22 Sep 2025 15:43:30 -0400 Subject: [PATCH 08/11] Bug fix --- .../cornellappdev/score/components/ScoreBox.kt | 18 +++++++++--------- .../score/util/TestingConstants.kt | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/com/cornellappdev/score/components/ScoreBox.kt b/app/src/main/java/com/cornellappdev/score/components/ScoreBox.kt index fdd3e11..6545dd9 100644 --- a/app/src/main/java/com/cornellappdev/score/components/ScoreBox.kt +++ b/app/src/main/java/com/cornellappdev/score/components/ScoreBox.kt @@ -110,8 +110,7 @@ private fun TeamNameColumn( //set to approximation of minimum width for "Cornell" modifier.widthIn(max = 70.dp) } else { - //can take up as much space as is available - modifier.width(IntrinsicSize.Max) + modifier.widthIn(max = 100.dp) } ) { Row( @@ -294,7 +293,7 @@ private fun CompleteTableData( teamTwoScores = gameData.teamScores.second, //if maxPeriods > 8, "Totals" header will wrap to two lines. In this case, don't weight so that space is allocated to TotalsColumn first //otherwise, TotalsColumn will fit without wrapping and can be allocated equal width as the data columns - modifier = if (maxPeriods < 8) { + modifier = if (maxPeriods < 4) { Modifier.weight(1f, fill = true) } else { Modifier @@ -386,38 +385,39 @@ private fun TotalsColumn( } +//Padding added to previews to simulate the padding around the ScoreBox when it's displayed on the screen @Preview @Composable private fun PreviewBoxScore() = ScorePreview { - BoxScore(gameData = gameData) + BoxScore(gameData = gameData, Modifier.padding(start = 20.dp, end = 20.dp)) } @Preview @Composable private fun PreviewBoxScoreForLongGame() = ScorePreview { - BoxScore(longGameData) + BoxScore(longGameData, Modifier.padding(start = 20.dp, end = 20.dp)) } @Preview @Composable private fun PreviewBoxScoreForMedGame() = ScorePreview { - BoxScore(mediumGameData) + BoxScore(mediumGameData, Modifier.padding(start = 20.dp, end = 20.dp)) } @Preview @Composable private fun PreviewBoxScoreForShortGame() = ScorePreview { - BoxScore(shortGameData) + BoxScore(shortGameData, Modifier.padding(start = 20.dp, end = 20.dp)) } @Preview @Composable private fun PreviewBoxScoreExtraLongGame() = ScorePreview { - BoxScore(gameData = extraLongGameData) + BoxScore(gameData = extraLongGameData, Modifier.padding(start = 20.dp, end = 20.dp)) } @Preview @Composable private fun PreviewBoxScoreEmpty() = ScorePreview { - BoxScore(gameData = emptyGameData()) + BoxScore(gameData = emptyGameData(), Modifier.padding(start = 20.dp, end = 20.dp)) } \ No newline at end of file diff --git a/app/src/main/java/com/cornellappdev/score/util/TestingConstants.kt b/app/src/main/java/com/cornellappdev/score/util/TestingConstants.kt index 64026a9..6f5cd35 100644 --- a/app/src/main/java/com/cornellappdev/score/util/TestingConstants.kt +++ b/app/src/main/java/com/cornellappdev/score/util/TestingConstants.kt @@ -55,7 +55,7 @@ val gameList = listOf( ) val team1 = TeamBoxScore(name = "Cornell") -val team2 = TeamBoxScore(name = "Yale") +val team2 = TeamBoxScore(name = "Yale University") val teamScore1 = TeamScore( team = team1, @@ -129,7 +129,7 @@ val team3 = TeamGameSummary( "https://cornellbigred.com/images/logos/penn_200x200.png?width=80&height=80&mode=max" ) val team4 = TeamGameSummary( - name = "Yale", + name = "Yale University", "https://cornellbigred.com/images/logos/penn_200x200.png?width=80&height=80&mode=max" ) val scoreEvents1 = listOf( From e98272dd553e12ebb2361637ca71ab56bd5d0755 Mon Sep 17 00:00:00 2001 From: amjiao Date: Wed, 1 Oct 2025 01:13:58 -0400 Subject: [PATCH 09/11] abstracted Lazy/DataRow (messed up weights) --- .../score/components/ScoreBox.kt | 134 +++++++++--------- .../com/cornellappdev/score/model/Game.kt | 43 +++--- 2 files changed, 92 insertions(+), 85 deletions(-) diff --git a/app/src/main/java/com/cornellappdev/score/components/ScoreBox.kt b/app/src/main/java/com/cornellappdev/score/components/ScoreBox.kt index 6545dd9..824f611 100644 --- a/app/src/main/java/com/cornellappdev/score/components/ScoreBox.kt +++ b/app/src/main/java/com/cornellappdev/score/components/ScoreBox.kt @@ -6,6 +6,7 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.IntrinsicSize import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding @@ -28,8 +29,8 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.cornellappdev.score.model.GameData +import com.cornellappdev.score.model.ScoresByPeriod import com.cornellappdev.score.model.TeamScore -import com.cornellappdev.score.model.mapToPeriodScores import com.cornellappdev.score.theme.CrimsonPrimary import com.cornellappdev.score.theme.GrayMedium import com.cornellappdev.score.theme.GrayPrimary @@ -44,23 +45,14 @@ import com.cornellappdev.score.util.mediumGameData import com.cornellappdev.score.util.shortGameData private val HEADER_HEIGHT = 35.dp +private val SMALL_BOX_SIZE = 4 +private val LARGE_BOX_SIZE = 10 @Composable fun BoxScore( gameData: GameData, modifier: Modifier = Modifier ) { - val maxPeriods = maxOf( - gameData.teamScores.first.scoresByPeriod.size, - gameData.teamScores.second.scoresByPeriod.size - ) - - val rowTextStyle = if (maxPeriods > 4) { - metricSmallNormal - } else { - metricNormal - } - Surface( modifier = modifier //set height required for CompleteLazyTableData case @@ -75,24 +67,21 @@ fun BoxScore( modifier = Modifier .fillMaxWidth() ) { + val rowTextStyle = if (gameData.maxPeriods > SMALL_BOX_SIZE) { + metricSmallNormal + } else { + metricNormal + } TeamNameColumn( gameData.teamScores.first.team.name, gameData.teamScores.second.team.name, rowTextStyle, - maxPeriods + gameData.maxPeriods + ) + CompleteTableData( + gameData = gameData, + rowTextStyle = rowTextStyle ) - if (maxPeriods > 10) { - CompleteLazyTableData( - gameData = gameData, - rowTextStyle = rowTextStyle - ) - } else { - CompleteTableData( - gameData = gameData, - rowTextStyle = rowTextStyle, - maxPeriods = maxPeriods - ) - } } } } @@ -113,13 +102,13 @@ private fun TeamNameColumn( modifier.widthIn(max = 100.dp) } ) { - Row( + Spacer( modifier = Modifier .fillMaxWidth() .background(color = CrimsonPrimary) .height(HEADER_HEIGHT) .padding(top = 6.dp, bottom = 4.dp), - ) {} + ) Row( modifier = Modifier .fillMaxWidth() @@ -221,54 +210,37 @@ private fun TableDataColumn( } @Composable -private fun CompleteLazyTableData( - gameData: GameData, +private fun LazyDataRow( + periodScores: List, rowTextStyle: TextStyle, modifier: Modifier = Modifier ) { - val periodScores = mapToPeriodScores(gameData) - - if (periodScores.isNotEmpty()) { - Row( - modifier = modifier - ) { - LazyRow( - modifier = Modifier.weight(1f) - ) { - items(periodScores) { periodScore -> - TableDataColumn( - header = periodScore.header, - teamOneScore = periodScore.teamOneScore, - teamTwoScore = periodScore.teamTwoScore, - rowTextStyle = rowTextStyle, - modifier = Modifier.width(35.dp) - ) - } - } - TotalsColumn( - teamOneScores = gameData.teamScores.first, - teamTwoScores = gameData.teamScores.second, - rowTextStyle = rowTextStyle + LazyRow( + modifier = modifier + ) { + items(periodScores) { periodScore -> + TableDataColumn( + header = periodScore.header, + teamOneScore = periodScore.teamOneScore, + teamTwoScore = periodScore.teamTwoScore, + rowTextStyle = rowTextStyle, + modifier = Modifier.width(35.dp) ) } } } @Composable -private fun CompleteTableData( - gameData: GameData, +private fun DataRow( + periodScores: List, rowTextStyle: TextStyle, - maxPeriods: Int, modifier: Modifier = Modifier ) { - val periodScores = mapToPeriodScores(gameData) - Row( - modifier = modifier, - horizontalArrangement = Arrangement.SpaceEvenly + modifier = modifier.fillMaxWidth() ) { if (periodScores.isNotEmpty()) { - mapToPeriodScores(gameData).map { periodScore -> + periodScores.map { periodScore -> TableDataColumn( header = periodScore.header, teamOneScore = periodScore.teamOneScore, @@ -288,20 +260,47 @@ private fun CompleteTableData( ) } } + } +} + +@Composable +private fun CompleteTableData( + gameData: GameData, + rowTextStyle: TextStyle, + modifier: Modifier = Modifier +) { + val periodScores = gameData.mapToPeriodScores() + + Row( + modifier = modifier + ) { + if (gameData.maxPeriods > LARGE_BOX_SIZE) { + LazyDataRow( + periodScores, + rowTextStyle, + Modifier.weight(1f) + ) + } else { + DataRow( + periodScores, + rowTextStyle, + Modifier.weight(1f) + ) + } + TotalsColumn( teamOneScores = gameData.teamScores.first, teamTwoScores = gameData.teamScores.second, + rowTextStyle = rowTextStyle, //if maxPeriods > 8, "Totals" header will wrap to two lines. In this case, don't weight so that space is allocated to TotalsColumn first //otherwise, TotalsColumn will fit without wrapping and can be allocated equal width as the data columns - modifier = if (maxPeriods < 4) { + modifier = if (gameData.maxPeriods < 4) { Modifier.weight(1f, fill = true) } else { Modifier - }, - rowTextStyle = rowTextStyle + } ) } - } @Composable @@ -324,7 +323,8 @@ private fun TotalScoreCell( style = rowTextStyle, color = if (showEmpty) Color.Gray else totalTextColor, fontWeight = if (showEmpty) FontWeight.Normal else FontWeight.Bold, - textAlign = TextAlign.Center + textAlign = TextAlign.Center, + modifier = Modifier.fillMaxWidth() ) } } @@ -351,9 +351,9 @@ private fun TotalsColumn( ) { Text( text = "Total", - color = Color.White, style = rowTextStyle, - textAlign = TextAlign.Center + textAlign = TextAlign.Center, + color = Color.White ) } 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 6ae6647..d6c93d7 100644 --- a/app/src/main/java/com/cornellappdev/score/model/Game.kt +++ b/app/src/main/java/com/cornellappdev/score/model/Game.kt @@ -146,7 +146,31 @@ data class TeamScore( // Aggregated game data showing scores for both teams data class GameData( val teamScores: Pair -) +){ + val maxPeriods: Int + get() = + maxOf( + teamScores.first.scoresByPeriod.size, + teamScores.second.scoresByPeriod.size + ) + + fun mapToPeriodScores(): List { + val teamOneScores = this.teamScores.first.scoresByPeriod + val teamTwoScores = this.teamScores.second.scoresByPeriod + + val maxPeriods = maxOf(teamOneScores.size, teamTwoScores.size) + + return (0 until maxPeriods).map { i -> + ScoresByPeriod( + header = i + 1, + teamOneScore = teamOneScores.getOrNull(i)?.toString() ?: "-", + teamTwoScore = teamTwoScores.getOrNull(i)?.toString() ?: "-" + + ) + + } + } +} /** * Represents a scoring event in a game. @@ -298,21 +322,4 @@ fun List.toScoreEvents(teamLogo: String): List description = boxScore.description ) } -} - -fun mapToPeriodScores(gameData: GameData): List { - val teamOneScores = gameData.teamScores.first.scoresByPeriod - val teamTwoScores = gameData.teamScores.second.scoresByPeriod - - val maxPeriods = maxOf(teamOneScores.size, teamTwoScores.size) - - return (0 until maxPeriods).map { i -> - ScoresByPeriod( - header = i + 1, - teamOneScore = teamOneScores.getOrNull(i)?.toString() ?: "-", - teamTwoScore = teamTwoScores.getOrNull(i)?.toString() ?: "-" - - ) - - } } \ No newline at end of file From 3c930a2268749db0f9ab9512b3f85d2c89ee8485 Mon Sep 17 00:00:00 2001 From: amjiao Date: Wed, 1 Oct 2025 09:21:01 -0400 Subject: [PATCH 10/11] reverted DataRow to less abstracted, resolved remaining comments --- .../score/components/ScoreBox.kt | 154 ++++++++---------- 1 file changed, 70 insertions(+), 84 deletions(-) diff --git a/app/src/main/java/com/cornellappdev/score/components/ScoreBox.kt b/app/src/main/java/com/cornellappdev/score/components/ScoreBox.kt index 824f611..35013c9 100644 --- a/app/src/main/java/com/cornellappdev/score/components/ScoreBox.kt +++ b/app/src/main/java/com/cornellappdev/score/components/ScoreBox.kt @@ -27,6 +27,8 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.tooling.preview.PreviewParameter +import androidx.compose.ui.tooling.preview.PreviewParameterProvider import androidx.compose.ui.unit.dp import com.cornellappdev.score.model.GameData import com.cornellappdev.score.model.ScoresByPeriod @@ -78,10 +80,18 @@ fun BoxScore( rowTextStyle, gameData.maxPeriods ) - CompleteTableData( - gameData = gameData, - rowTextStyle = rowTextStyle - ) + if (gameData.maxPeriods > LARGE_BOX_SIZE) { + CompleteLazyTableData( + gameData = gameData, + rowTextStyle = rowTextStyle + ) + } else { + CompleteTableData( + gameData = gameData, + rowTextStyle = rowTextStyle, + maxPeriods = gameData.maxPeriods + ) + } } } } @@ -210,35 +220,53 @@ private fun TableDataColumn( } @Composable -private fun LazyDataRow( - periodScores: List, +private fun CompleteLazyTableData( + gameData: GameData, rowTextStyle: TextStyle, modifier: Modifier = Modifier ) { - LazyRow( - modifier = modifier - ) { - items(periodScores) { periodScore -> - TableDataColumn( - header = periodScore.header, - teamOneScore = periodScore.teamOneScore, - teamTwoScore = periodScore.teamTwoScore, - rowTextStyle = rowTextStyle, - modifier = Modifier.width(35.dp) + val periodScores = gameData.mapToPeriodScores() + + if (periodScores.isNotEmpty()) { + Row( + modifier = modifier + ) { + LazyRow( + modifier = Modifier.weight(1f) + ) { + items(periodScores) { periodScore -> + TableDataColumn( + header = periodScore.header, + teamOneScore = periodScore.teamOneScore, + teamTwoScore = periodScore.teamTwoScore, + rowTextStyle = rowTextStyle, + modifier = Modifier.width(35.dp) + ) + } + } + TotalsColumn( + teamOneScores = gameData.teamScores.first, + teamTwoScores = gameData.teamScores.second, + rowTextStyle = rowTextStyle ) } } } @Composable -private fun DataRow( - periodScores: List, +private fun CompleteTableData( + gameData: GameData, rowTextStyle: TextStyle, + maxPeriods: Int, modifier: Modifier = Modifier ) { + val periodScores = gameData.mapToPeriodScores() + Row( - modifier = modifier.fillMaxWidth() + modifier = modifier, + horizontalArrangement = Arrangement.SpaceEvenly ) { + if (periodScores.isNotEmpty()) { periodScores.map { periodScore -> TableDataColumn( @@ -260,45 +288,17 @@ private fun DataRow( ) } } - } -} - -@Composable -private fun CompleteTableData( - gameData: GameData, - rowTextStyle: TextStyle, - modifier: Modifier = Modifier -) { - val periodScores = gameData.mapToPeriodScores() - - Row( - modifier = modifier - ) { - if (gameData.maxPeriods > LARGE_BOX_SIZE) { - LazyDataRow( - periodScores, - rowTextStyle, - Modifier.weight(1f) - ) - } else { - DataRow( - periodScores, - rowTextStyle, - Modifier.weight(1f) - ) - } - TotalsColumn( teamOneScores = gameData.teamScores.first, teamTwoScores = gameData.teamScores.second, - rowTextStyle = rowTextStyle, //if maxPeriods > 8, "Totals" header will wrap to two lines. In this case, don't weight so that space is allocated to TotalsColumn first - //otherwise, TotalsColumn will fit without wrapping and can be allocated equal width as the data columns - modifier = if (gameData.maxPeriods < 4) { +//otherwise, TotalsColumn will fit without wrapping and can be allocated equal width as the data columns + modifier = if (maxPeriods < 4) { Modifier.weight(1f, fill = true) } else { Modifier - } + }, + rowTextStyle = rowTextStyle ) } } @@ -384,40 +384,26 @@ private fun TotalsColumn( } } - -//Padding added to previews to simulate the padding around the ScoreBox when it's displayed on the screen -@Preview -@Composable -private fun PreviewBoxScore() = ScorePreview { - BoxScore(gameData = gameData, Modifier.padding(start = 20.dp, end = 20.dp)) -} - -@Preview -@Composable -private fun PreviewBoxScoreForLongGame() = ScorePreview { - BoxScore(longGameData, Modifier.padding(start = 20.dp, end = 20.dp)) -} - -@Preview -@Composable -private fun PreviewBoxScoreForMedGame() = ScorePreview { - BoxScore(mediumGameData, Modifier.padding(start = 20.dp, end = 20.dp)) -} - -@Preview -@Composable -private fun PreviewBoxScoreForShortGame() = ScorePreview { - BoxScore(shortGameData, Modifier.padding(start = 20.dp, end = 20.dp)) -} - -@Preview -@Composable -private fun PreviewBoxScoreExtraLongGame() = ScorePreview { - BoxScore(gameData = extraLongGameData, Modifier.padding(start = 20.dp, end = 20.dp)) +class GameDataPreviewProvider : PreviewParameterProvider { + override val values: Sequence = sequenceOf( + gameData, + longGameData, + mediumGameData, + shortGameData, + extraLongGameData, + emptyGameData() + ) } -@Preview +@Preview(showBackground = true) @Composable -private fun PreviewBoxScoreEmpty() = ScorePreview { - BoxScore(gameData = emptyGameData(), Modifier.padding(start = 20.dp, end = 20.dp)) +private fun BoxScoreParameterizedPreview( + @PreviewParameter(GameDataPreviewProvider::class) sample: GameData +) { + ScorePreview { + BoxScore( + gameData = sample, + modifier = Modifier.padding(start = 20.dp, end = 20.dp) + ) + } } \ No newline at end of file From b7292ec18f37a979d0c04c757f638e0e84c08f25 Mon Sep 17 00:00:00 2001 From: amjiao Date: Wed, 1 Oct 2025 15:31:22 -0400 Subject: [PATCH 11/11] made local constants const --- .../main/java/com/cornellappdev/score/components/ScoreBox.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/cornellappdev/score/components/ScoreBox.kt b/app/src/main/java/com/cornellappdev/score/components/ScoreBox.kt index 35013c9..e6a7951 100644 --- a/app/src/main/java/com/cornellappdev/score/components/ScoreBox.kt +++ b/app/src/main/java/com/cornellappdev/score/components/ScoreBox.kt @@ -47,8 +47,8 @@ import com.cornellappdev.score.util.mediumGameData import com.cornellappdev.score.util.shortGameData private val HEADER_HEIGHT = 35.dp -private val SMALL_BOX_SIZE = 4 -private val LARGE_BOX_SIZE = 10 +private const val SMALL_BOX_SIZE = 4 +private const val LARGE_BOX_SIZE = 10 @Composable fun BoxScore(