From 9089e1bff447842b3972796799e673e476797657 Mon Sep 17 00:00:00 2001 From: amjiao Date: Wed, 15 Oct 2025 15:53:10 -0400 Subject: [PATCH 01/17] Highlights Card UI --- .../score/components/HighlightsCard.kt | 260 ++++++++++++++++++ .../cornellappdev/score/model/Highlights.kt | 10 + .../main/res/drawable/arrow_outward_red.xml | 13 + .../main/res/drawable/arrow_outward_white.xml | 13 + 4 files changed, 296 insertions(+) create mode 100644 app/src/main/java/com/cornellappdev/score/components/HighlightsCard.kt create mode 100644 app/src/main/java/com/cornellappdev/score/model/Highlights.kt create mode 100644 app/src/main/res/drawable/arrow_outward_red.xml create mode 100644 app/src/main/res/drawable/arrow_outward_white.xml diff --git a/app/src/main/java/com/cornellappdev/score/components/HighlightsCard.kt b/app/src/main/java/com/cornellappdev/score/components/HighlightsCard.kt new file mode 100644 index 0000000..c53b2da --- /dev/null +++ b/app/src/main/java/com/cornellappdev/score/components/HighlightsCard.kt @@ -0,0 +1,260 @@ +package com.cornellappdev.score.components + +import androidx.compose.foundation.Image +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.Row +import androidx.compose.foundation.layout.Spacer +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.foundation.text.BasicText +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.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.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.GenderDivision +import com.cornellappdev.score.model.HighlightCard +import com.cornellappdev.score.model.Sport +import com.cornellappdev.score.theme.CrimsonPrimary +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 + +@Composable +fun VideoHighlightCardHeader( + image: String +) { + Box( + modifier = Modifier + .width(241.dp) + .height(117.dp) + .clip(RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp)) + .background(color = Color.Blue) + ) { + AsyncImage( + model = image, + contentDescription = "Highlight article image" + ) + Box( + modifier = Modifier + .fillMaxSize() + .background(color = Color.Black.copy(alpha = 0.4f)) + + ) + } +} + +@Composable +fun VideoHighlightCard( + videoHighlight: HighlightCard, + modifier: Modifier = Modifier +) { + Column( + modifier = modifier + ) { + VideoHighlightCardHeader(videoHighlight.image) + + Column( + modifier = Modifier + .width(241.dp) + .height(75.dp) + .background(color = Color.White) + .padding(horizontal = 16.dp, vertical = 8.dp), + ) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + style = heading2, + text = videoHighlight.title + ) + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Image( + painter = painterResource(videoHighlight.sport.emptyIcon), + contentDescription = "Sport icon", + modifier = Modifier + .width(24.dp) + .height(24.dp) + ) + Image( + painter = painterResource(if (videoHighlight.gender == GenderDivision.FEMALE) R.drawable.ic_gender_women else R.drawable.ic_gender_men), + contentDescription = "Gender icon" + ) + } + } + Spacer(Modifier.height(8.dp)) + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Row( + verticalAlignment = Alignment.CenterVertically + ) { + BasicText( + text = buildAnnotatedString { + withLink( + LinkAnnotation.Url( + "https://developer.android.com/jetpack/compose", + TextLinkStyles( + style = SpanStyle( + textDecoration = TextDecoration.Underline, + color = CrimsonPrimary + ) + ), + ) + ) { + append("YouTube") + } + } + ) + Image( + painter = painterResource(R.drawable.arrow_outward_red), + contentDescription = "external link arrow" + ) + } + Text( + style = labelsNormal, + text = "11/09" + ) + } + } + } +} + +@Composable +fun ArticleHighlightCard( + articleHighlight: HighlightCard, + modifier: Modifier = Modifier +) { + Box( + modifier = modifier + .width(241.dp) + .height(192.dp) + .clip(shape = RoundedCornerShape(12.dp)) + .background(color = Color.Blue) + ) { + AsyncImage( + model = articleHighlight.image, + contentDescription = "highlight image" + ) + Box( + modifier = Modifier + .fillMaxSize() + .background(color = Color.Black.copy(alpha = 0.4f)) + + ) + Column( + modifier = Modifier + .fillMaxSize() + .padding(12.dp), + verticalArrangement = Arrangement.SpaceBetween + ) { + Text( + style = heading2, + color = Color.White, + text = articleHighlight.title + ) + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Row( + verticalAlignment = Alignment.CenterVertically + ) { + BasicText( + style = bodySemibold, + text = buildAnnotatedString { + withLink( + LinkAnnotation.Url( + "https://developer.android.com/jetpack/compose", + TextLinkStyles( + style = SpanStyle( + textDecoration = TextDecoration.Underline, + color = White + ) + ), + ) + ) { + append("Cornell Daily Sun") + } + } + ) + Image( + painter = painterResource(R.drawable.arrow_outward_white), + contentDescription = "external link arrow" + ) + } + Text( + color = Color.White, + style = labelsNormal, + text = "11/09" + ) + } + } + } +} + +@Preview +@Composable +private fun ArticleHighlightCardPreview() { + ArticleHighlightCard( + HighlightCard( + "Late Goal Lifts No. 6 Men’s Hockey Over Brown", + "maxresdefault.jpg", + "https://cornellsun.com/article/london-mcdavid-is-making-a-name-for-herself-at-cornell", + "11/9", + Sport.BASEBALL, + GenderDivision.MALE + ) + ) +} + +@Preview +@Composable +private fun VideoHighlightCardHeaderPreview() { + VideoHighlightCardHeader( + "image_placeholder" + ) +} + +@Preview +@Composable +private fun VideoHighlightCardPreview() { + VideoHighlightCard( + HighlightCard( + "vs Columbia", + "maxresdefault.jpg", + "https://cornellsun.com/article/london-mcdavid-is-making-a-name-for-herself-at-cornell", + "11/9", + Sport.BASEBALL, + GenderDivision.MALE + ) + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/cornellappdev/score/model/Highlights.kt b/app/src/main/java/com/cornellappdev/score/model/Highlights.kt new file mode 100644 index 0000000..ad94756 --- /dev/null +++ b/app/src/main/java/com/cornellappdev/score/model/Highlights.kt @@ -0,0 +1,10 @@ +package com.cornellappdev.score.model + +data class HighlightCard( + val title: String, + val image: String, + val url: String, + val date: String, + val sport: Sport, + val gender: GenderDivision +) \ No newline at end of file diff --git a/app/src/main/res/drawable/arrow_outward_red.xml b/app/src/main/res/drawable/arrow_outward_red.xml new file mode 100644 index 0000000..6ae84d7 --- /dev/null +++ b/app/src/main/res/drawable/arrow_outward_red.xml @@ -0,0 +1,13 @@ + + + + + + diff --git a/app/src/main/res/drawable/arrow_outward_white.xml b/app/src/main/res/drawable/arrow_outward_white.xml new file mode 100644 index 0000000..c55592c --- /dev/null +++ b/app/src/main/res/drawable/arrow_outward_white.xml @@ -0,0 +1,13 @@ + + + + + + \ No newline at end of file From 2beedca136921c4361cf4cf7344b184b8ea73cbe Mon Sep 17 00:00:00 2001 From: amjiao Date: Wed, 22 Oct 2025 00:04:07 -0400 Subject: [PATCH 02/17] Added wide highlight card case and handled title line overflow --- .../score/components/HighlightsCard.kt | 106 +++++++++++++++--- .../score/util/TestingConstants.kt | 45 ++++++++ 2 files changed, 133 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/com/cornellappdev/score/components/HighlightsCard.kt b/app/src/main/java/com/cornellappdev/score/components/HighlightsCard.kt index c53b2da..32f80fd 100644 --- a/app/src/main/java/com/cornellappdev/score/components/HighlightsCard.kt +++ b/app/src/main/java/com/cornellappdev/score/components/HighlightsCard.kt @@ -2,6 +2,7 @@ package com.cornellappdev.score.components import androidx.compose.foundation.Image import androidx.compose.foundation.background +import androidx.compose.foundation.border import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -26,6 +27,7 @@ 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 @@ -35,6 +37,7 @@ import com.cornellappdev.score.model.GenderDivision import com.cornellappdev.score.model.HighlightCard import com.cornellappdev.score.model.Sport import com.cornellappdev.score.theme.CrimsonPrimary +import com.cornellappdev.score.theme.GrayStroke import com.cornellappdev.score.theme.Style.bodySemibold import com.cornellappdev.score.theme.Style.heading2 import com.cornellappdev.score.theme.Style.labelsNormal @@ -46,10 +49,9 @@ fun VideoHighlightCardHeader( ) { Box( modifier = Modifier - .width(241.dp) + .fillMaxWidth() .height(117.dp) .clip(RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp)) - .background(color = Color.Blue) ) { AsyncImage( model = image, @@ -59,7 +61,6 @@ fun VideoHighlightCardHeader( modifier = Modifier .fillMaxSize() .background(color = Color.Black.copy(alpha = 0.4f)) - ) } } @@ -67,18 +68,24 @@ fun VideoHighlightCardHeader( @Composable fun VideoHighlightCard( videoHighlight: HighlightCard, + wide: Boolean, modifier: Modifier = Modifier ) { Column( - modifier = modifier + modifier = if (wide) modifier.fillMaxWidth() else modifier.width(241.dp) ) { VideoHighlightCardHeader(videoHighlight.image) Column( modifier = Modifier - .width(241.dp) .height(75.dp) + .clip(RoundedCornerShape(bottomStart = 12.dp, bottomEnd = 12.dp)) .background(color = Color.White) + .border( + width = 1.dp, + color = GrayStroke, + shape = RoundedCornerShape(bottomStart = 12.dp, bottomEnd = 12.dp) + ) .padding(horizontal = 16.dp, vertical = 8.dp), ) { Row( @@ -87,8 +94,11 @@ fun VideoHighlightCard( verticalAlignment = Alignment.CenterVertically ) { Text( + modifier = Modifier.weight(1f), style = heading2, - text = videoHighlight.title + text = videoHighlight.title, + maxLines = 1, + overflow = TextOverflow.Ellipsis ) Row( verticalAlignment = Alignment.CenterVertically @@ -119,7 +129,7 @@ fun VideoHighlightCard( text = buildAnnotatedString { withLink( LinkAnnotation.Url( - "https://developer.android.com/jetpack/compose", + videoHighlight.url, TextLinkStyles( style = SpanStyle( textDecoration = TextDecoration.Underline, @@ -149,14 +159,15 @@ fun VideoHighlightCard( @Composable fun ArticleHighlightCard( articleHighlight: HighlightCard, + wide: Boolean, modifier: Modifier = Modifier ) { Box( - modifier = modifier - .width(241.dp) + modifier = modifier.then( + if (wide) Modifier.fillMaxWidth() else Modifier.width(241.dp) + ) .height(192.dp) .clip(shape = RoundedCornerShape(12.dp)) - .background(color = Color.Blue) ) { AsyncImage( model = articleHighlight.image, @@ -177,7 +188,9 @@ fun ArticleHighlightCard( Text( style = heading2, color = Color.White, - text = articleHighlight.title + text = articleHighlight.title, + maxLines = 4, + overflow = TextOverflow.Ellipsis ) Row( @@ -193,7 +206,7 @@ fun ArticleHighlightCard( text = buildAnnotatedString { withLink( LinkAnnotation.Url( - "https://developer.android.com/jetpack/compose", + articleHighlight.url, TextLinkStyles( style = SpanStyle( textDecoration = TextDecoration.Underline, @@ -232,15 +245,23 @@ private fun ArticleHighlightCardPreview() { "11/9", Sport.BASEBALL, GenderDivision.MALE - ) + ), + false ) } - @Preview @Composable -private fun VideoHighlightCardHeaderPreview() { - VideoHighlightCardHeader( - "image_placeholder" +private fun WideArticleHighlightCardPreview() { + ArticleHighlightCard( + HighlightCard( + "Late Goal Lifts No. 6 Men’s Hockey Over Brown", + "maxresdefault.jpg", + "https://cornellsun.com/article/london-mcdavid-is-making-a-name-for-herself-at-cornell", + "11/9", + Sport.BASEBALL, + GenderDivision.MALE + ), + true ) } @@ -255,6 +276,55 @@ private fun VideoHighlightCardPreview() { "11/9", Sport.BASEBALL, GenderDivision.MALE - ) + ), + false + ) +} + +@Preview +@Composable +private fun WideVideoHighlightCardPreview() { + VideoHighlightCard( + HighlightCard( + "vs Columbia", + "maxresdefault.jpg", + "https://cornellsun.com/article/london-mcdavid-is-making-a-name-for-herself-at-cornell", + "11/9", + Sport.BASEBALL, + GenderDivision.MALE + ), + true + ) +} + +@Preview +@Composable +private fun OverflowVideoHighlightCardPreview() { + VideoHighlightCard( + HighlightCard( + "Late Goal Lifts No. 6 Men’s Hockey Over Brown", + "maxresdefault.jpg", + "https://cornellsun.com/article/london-mcdavid-is-making-a-name-for-herself-at-cornell", + "11/9", + Sport.BASEBALL, + GenderDivision.MALE + ), + false + ) +} + +@Preview +@Composable +private fun WideOverflowVideoHighlightCardPreview() { + VideoHighlightCard( + HighlightCard( + "Late Goal Lifts No. 6 Men’s Hockey Over Brown", + "maxresdefault.jpg", + "https://cornellsun.com/article/london-mcdavid-is-making-a-name-for-herself-at-cornell", + "11/9", + Sport.BASEBALL, + GenderDivision.MALE + ), + true ) } \ 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 6f5cd35..8e046c8 100644 --- a/app/src/main/java/com/cornellappdev/score/util/TestingConstants.kt +++ b/app/src/main/java/com/cornellappdev/score/util/TestingConstants.kt @@ -4,6 +4,8 @@ import androidx.compose.ui.graphics.Color import com.cornellappdev.score.R import com.cornellappdev.score.model.GameCardData import com.cornellappdev.score.model.GameData +import com.cornellappdev.score.model.GenderDivision +import com.cornellappdev.score.model.HighlightCard import com.cornellappdev.score.model.ScoreEvent import com.cornellappdev.score.model.Sport import com.cornellappdev.score.model.SportSelection @@ -217,3 +219,46 @@ val sportSelectionList = listOf( SportSelection.SportSelect(Sport.BASKETBALL), SportSelection.SportSelect(Sport.CROSS_COUNTRY), ) + +val highlightsList = listOf( + HighlightCard( + "vs Columbia", + "maxresdefault.jpg", + "https://cornellsun.com/article/london-mcdavid-is-making-a-name-for-herself-at-cornell", + "11/09", + Sport.BASEBALL, + GenderDivision.MALE + ), + HighlightCard( + "Late Goal Lifts No. 6 Men’s Hockey Over Brown", + "maxresdefault.jpg", + "https://cornellsun.com/article/london-mcdavid-is-making-a-name-for-herself-at-cornell", + "11/09", + Sport.BASEBALL, + GenderDivision.MALE + ), + HighlightCard( + "vs Columbia", + "maxresdefault.jpg", + "https://cornellsun.com/article/london-mcdavid-is-making-a-name-for-herself-at-cornell", + "11/9", + Sport.BASEBALL, + GenderDivision.MALE + ), + HighlightCard( + "Late Goal Lifts No. 6 Men’s Hockey Over Brown", + "maxresdefault.jpg", + "https://cornellsun.com/article/london-mcdavid-is-making-a-name-for-herself-at-cornell", + "11/09", + Sport.BASEBALL, + GenderDivision.MALE + ), + HighlightCard( + "vs Columbia", + "maxresdefault.jpg", + "https://cornellsun.com/article/london-mcdavid-is-making-a-name-for-herself-at-cornell", + "11/9", + Sport.BASEBALL, + GenderDivision.MALE + ) +) \ No newline at end of file From f953e24078b0548ef646ab743918d12206b33211 Mon Sep 17 00:00:00 2001 From: amjiao Date: Wed, 22 Oct 2025 00:04:38 -0400 Subject: [PATCH 03/17] filter button for highlights screen --- .../components/HighlightsFilterButton.kt | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 app/src/main/java/com/cornellappdev/score/components/HighlightsFilterButton.kt diff --git a/app/src/main/java/com/cornellappdev/score/components/HighlightsFilterButton.kt b/app/src/main/java/com/cornellappdev/score/components/HighlightsFilterButton.kt new file mode 100644 index 0000000..1334640 --- /dev/null +++ b/app/src/main/java/com/cornellappdev/score/components/HighlightsFilterButton.kt @@ -0,0 +1,58 @@ +package com.cornellappdev.score.components + +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.height +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.unit.dp +import com.cornellappdev.score.model.Sport +import com.cornellappdev.score.theme.Style.bodyNormal +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.ui.Alignment +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.tooling.preview.Preview +import com.cornellappdev.score.theme.GrayStroke + +@Composable +fun HighlightsFilterButton( + sport: Sport +){ + Row( + modifier = Modifier.height(32.dp) + .clip(shape = RoundedCornerShape(100)) + .background(color = Color.White) + .border( + width = 1.dp, + color = GrayStroke, + shape = RoundedCornerShape(100) + ) + .padding(horizontal = 12.dp, vertical = 4.dp), + verticalAlignment = Alignment.CenterVertically, + + ){ + Image( + painter = painterResource(sport.emptyIcon), + contentDescription = "sport Icon" + ) + Spacer(modifier = Modifier.width(4.dp)) + Text( + text = sport.displayName, + style = bodyNormal + ) + } +} + +@Preview +@Composable +private fun HighlightsFilterButtonPreview(){ + HighlightsFilterButton(Sport.BASEBALL) +} \ No newline at end of file From b3678694cb539bb8871cc17854efe7304ca5bd2a Mon Sep 17 00:00:00 2001 From: amjiao Date: Wed, 22 Oct 2025 00:17:14 -0400 Subject: [PATCH 04/17] made highlights filter button clickable --- .../components/HighlightsFilterButton.kt | 41 ++++++++++--------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/com/cornellappdev/score/components/HighlightsFilterButton.kt b/app/src/main/java/com/cornellappdev/score/components/HighlightsFilterButton.kt index 1334640..f8c2188 100644 --- a/app/src/main/java/com/cornellappdev/score/components/HighlightsFilterButton.kt +++ b/app/src/main/java/com/cornellappdev/score/components/HighlightsFilterButton.kt @@ -1,44 +1,47 @@ package com.cornellappdev.score.components -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.height -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.unit.dp -import com.cornellappdev.score.model.Sport -import com.cornellappdev.score.theme.Style.bodyNormal import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +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.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.res.painterResource import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.cornellappdev.score.model.Sport import com.cornellappdev.score.theme.GrayStroke +import com.cornellappdev.score.theme.Style.bodyNormal @Composable fun HighlightsFilterButton( - sport: Sport -){ + sport: Sport, + onClick: () -> Unit +) { Row( - modifier = Modifier.height(32.dp) - .clip(shape = RoundedCornerShape(100)) - .background(color = Color.White) + modifier = Modifier + .height(32.dp) .border( width = 1.dp, color = GrayStroke, shape = RoundedCornerShape(100) ) - .padding(horizontal = 12.dp, vertical = 4.dp), + .background(color = Color.White, shape = RoundedCornerShape(100)) + .padding(horizontal = 12.dp, vertical = 4.dp) + .clip(shape = RoundedCornerShape(100)) + .clickable { onClick }, verticalAlignment = Alignment.CenterVertically, - - ){ + ) { Image( painter = painterResource(sport.emptyIcon), contentDescription = "sport Icon" @@ -53,6 +56,6 @@ fun HighlightsFilterButton( @Preview @Composable -private fun HighlightsFilterButtonPreview(){ - HighlightsFilterButton(Sport.BASEBALL) +private fun HighlightsFilterButtonPreview() { + HighlightsFilterButton(Sport.BASEBALL, {}) } \ No newline at end of file From de6739212c18047d7ea074ec5e11270a4b1c4516 Mon Sep 17 00:00:00 2001 From: amjiao Date: Wed, 22 Oct 2025 00:17:54 -0400 Subject: [PATCH 05/17] highlights screen --- .../score/screen/HighlightsScreen.kt | 184 ++++++++++++++++++ app/src/main/res/drawable/search.xml | 13 ++ 2 files changed, 197 insertions(+) create mode 100644 app/src/main/java/com/cornellappdev/score/screen/HighlightsScreen.kt create mode 100644 app/src/main/res/drawable/search.xml diff --git a/app/src/main/java/com/cornellappdev/score/screen/HighlightsScreen.kt b/app/src/main/java/com/cornellappdev/score/screen/HighlightsScreen.kt new file mode 100644 index 0000000..4385bc9 --- /dev/null +++ b/app/src/main/java/com/cornellappdev/score/screen/HighlightsScreen.kt @@ -0,0 +1,184 @@ +package com.cornellappdev.score.screen + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +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.lazy.LazyRow +import androidx.compose.foundation.shape.RoundedCornerShape +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.BlendMode +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.cornellappdev.score.R +import com.cornellappdev.score.components.ArticleHighlightCard +import com.cornellappdev.score.components.HighlightsFilterButton +import com.cornellappdev.score.components.VideoHighlightCard +import com.cornellappdev.score.model.HighlightCard +import com.cornellappdev.score.model.Sport +import com.cornellappdev.score.theme.GrayLight +import com.cornellappdev.score.theme.GrayMedium +import com.cornellappdev.score.theme.Style.bodyNormal +import com.cornellappdev.score.theme.Style.heading1 +import com.cornellappdev.score.theme.Style.heading2 +import com.cornellappdev.score.util.highlightsList +import com.cornellappdev.score.util.sportList + +@Composable +fun HighlightsScreen( + todayHighlightsList: List, + pastThreeHighlightsList: List, + filtersList: List +) { + Column( + modifier = Modifier + .fillMaxSize() + .background(color = Color.White) + ) { + Spacer(modifier = Modifier.height(24.dp)) + Text( + modifier = Modifier.padding(start = 24.dp), + style = heading1, + text = "Highlights" + ) + Spacer(modifier = Modifier.height(12.dp)) + Row( + modifier = Modifier + .padding(horizontal = 24.dp) + .border(width = 1.dp, color = GrayLight, shape = RoundedCornerShape(100.dp)) + .background(color = Color.White, shape = RoundedCornerShape(100.dp)) + .fillMaxWidth() + .clip(shape = RoundedCornerShape(100.dp)) + .clickable {/*todo navigate to search screen*/ }, + verticalAlignment = Alignment.CenterVertically + ) { + Row( + modifier = Modifier.padding(8.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Image( + painter = painterResource(R.drawable.search), + contentDescription = "search icon" + ) + Spacer(modifier = Modifier.width(4.dp)) + Text( + text = "Search keywords", + style = bodyNormal + ) + } + } + Spacer(modifier = Modifier.height(16.dp)) + LazyRow( + modifier = Modifier + .fillMaxWidth() + .padding(start = 24.dp), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + items(filtersList.size) { i -> + HighlightsFilterButton(filtersList[i], {/*todo filter functionality*/ }) + Spacer(Modifier.width(12.dp)) + } + } + Spacer(modifier = Modifier.height(24.dp)) + Row( + modifier = Modifier + .padding(horizontal = 24.dp) + .fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "Today", + style = heading2 + ) + Row( + modifier = Modifier.clickable {/*todo navigation to Today screen*/ }, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "${todayHighlightsList.size} Results", + style = bodyNormal + ) + Image( + painter = painterResource(R.drawable.ic_right_chevron), + contentDescription = "right chevron", + colorFilter = ColorFilter.tint(GrayMedium, blendMode = BlendMode.SrcIn) + ) + } + } + Spacer(modifier = Modifier.height(16.dp)) + LazyRow( + modifier = Modifier.padding(start = 24.dp) + ) { + items(todayHighlightsList.size) { i -> + VideoHighlightCard( + todayHighlightsList[i], + false + ) + Spacer(modifier = Modifier.width(16.dp)) + } + } + Spacer(modifier = Modifier.height(24.dp)) + Row( + modifier = Modifier + .padding(horizontal = 24.dp) + .fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "Past 3 days", + style = heading2 + ) + Row( + modifier = Modifier.clickable {/*todo navigation to Past3Days screen*/ }, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "${pastThreeHighlightsList.size} Results", + style = bodyNormal + ) + Image( + painter = painterResource(R.drawable.ic_right_chevron), + contentDescription = "right chevron", + colorFilter = ColorFilter.tint(GrayMedium, blendMode = BlendMode.SrcIn) + ) + } + } + Spacer(modifier = Modifier.height(16.dp)) + LazyRow( + modifier = Modifier.padding(start = 24.dp) + ) { + items(pastThreeHighlightsList.size) { i -> + ArticleHighlightCard( + todayHighlightsList[i], + false + ) + Spacer(modifier = Modifier.width(16.dp)) + } + } + } +} + +@Composable +@Preview +private fun HighlightsScreenPreview() { + HighlightsScreen(highlightsList, highlightsList, sportList) +} \ No newline at end of file diff --git a/app/src/main/res/drawable/search.xml b/app/src/main/res/drawable/search.xml new file mode 100644 index 0000000..3243b22 --- /dev/null +++ b/app/src/main/res/drawable/search.xml @@ -0,0 +1,13 @@ + + + + + + From bd7b7fa334c8221f5bf32084f3c92075eb388390 Mon Sep 17 00:00:00 2001 From: amjiao Date: Fri, 24 Oct 2025 13:16:39 -0400 Subject: [PATCH 06/17] Some name changes --- .../score/components/HighlightsCard.kt | 27 ++-- ...htsFilterButton.kt => HighlightsFilter.kt} | 36 ++++- .../cornellappdev/score/model/Highlights.kt | 9 +- .../score/screen/HighlightsScreen.kt | 145 ++++++++++-------- .../score/util/TestingConstants.kt | 22 ++- 5 files changed, 139 insertions(+), 100 deletions(-) rename app/src/main/java/com/cornellappdev/score/components/{HighlightsFilterButton.kt => HighlightsFilter.kt} (68%) diff --git a/app/src/main/java/com/cornellappdev/score/components/HighlightsCard.kt b/app/src/main/java/com/cornellappdev/score/components/HighlightsCard.kt index 32f80fd..7e11e8f 100644 --- a/app/src/main/java/com/cornellappdev/score/components/HighlightsCard.kt +++ b/app/src/main/java/com/cornellappdev/score/components/HighlightsCard.kt @@ -33,8 +33,9 @@ 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.GenderDivision -import com.cornellappdev.score.model.HighlightCard +import com.cornellappdev.score.model.VideoHighlightData import com.cornellappdev.score.model.Sport import com.cornellappdev.score.theme.CrimsonPrimary import com.cornellappdev.score.theme.GrayStroke @@ -67,7 +68,7 @@ fun VideoHighlightCardHeader( @Composable fun VideoHighlightCard( - videoHighlight: HighlightCard, + videoHighlight: VideoHighlightData, wide: Boolean, modifier: Modifier = Modifier ) { @@ -158,7 +159,7 @@ fun VideoHighlightCard( @Composable fun ArticleHighlightCard( - articleHighlight: HighlightCard, + articleHighlight: ArticleHighlightData, wide: Boolean, modifier: Modifier = Modifier ) { @@ -238,13 +239,11 @@ fun ArticleHighlightCard( @Composable private fun ArticleHighlightCardPreview() { ArticleHighlightCard( - HighlightCard( + ArticleHighlightData( "Late Goal Lifts No. 6 Men’s Hockey Over Brown", "maxresdefault.jpg", "https://cornellsun.com/article/london-mcdavid-is-making-a-name-for-herself-at-cornell", - "11/9", - Sport.BASEBALL, - GenderDivision.MALE + "11/9" ), false ) @@ -253,13 +252,11 @@ private fun ArticleHighlightCardPreview() { @Composable private fun WideArticleHighlightCardPreview() { ArticleHighlightCard( - HighlightCard( + ArticleHighlightData( "Late Goal Lifts No. 6 Men’s Hockey Over Brown", "maxresdefault.jpg", "https://cornellsun.com/article/london-mcdavid-is-making-a-name-for-herself-at-cornell", - "11/9", - Sport.BASEBALL, - GenderDivision.MALE + "11/9" ), true ) @@ -269,7 +266,7 @@ private fun WideArticleHighlightCardPreview() { @Composable private fun VideoHighlightCardPreview() { VideoHighlightCard( - HighlightCard( + VideoHighlightData( "vs Columbia", "maxresdefault.jpg", "https://cornellsun.com/article/london-mcdavid-is-making-a-name-for-herself-at-cornell", @@ -285,7 +282,7 @@ private fun VideoHighlightCardPreview() { @Composable private fun WideVideoHighlightCardPreview() { VideoHighlightCard( - HighlightCard( + VideoHighlightData( "vs Columbia", "maxresdefault.jpg", "https://cornellsun.com/article/london-mcdavid-is-making-a-name-for-herself-at-cornell", @@ -301,7 +298,7 @@ private fun WideVideoHighlightCardPreview() { @Composable private fun OverflowVideoHighlightCardPreview() { VideoHighlightCard( - HighlightCard( + VideoHighlightData( "Late Goal Lifts No. 6 Men’s Hockey Over Brown", "maxresdefault.jpg", "https://cornellsun.com/article/london-mcdavid-is-making-a-name-for-herself-at-cornell", @@ -317,7 +314,7 @@ private fun OverflowVideoHighlightCardPreview() { @Composable private fun WideOverflowVideoHighlightCardPreview() { VideoHighlightCard( - HighlightCard( + VideoHighlightData( "Late Goal Lifts No. 6 Men’s Hockey Over Brown", "maxresdefault.jpg", "https://cornellsun.com/article/london-mcdavid-is-making-a-name-for-herself-at-cornell", diff --git a/app/src/main/java/com/cornellappdev/score/components/HighlightsFilterButton.kt b/app/src/main/java/com/cornellappdev/score/components/HighlightsFilter.kt similarity index 68% rename from app/src/main/java/com/cornellappdev/score/components/HighlightsFilterButton.kt rename to app/src/main/java/com/cornellappdev/score/components/HighlightsFilter.kt index f8c2188..1eb9e4f 100644 --- a/app/src/main/java/com/cornellappdev/score/components/HighlightsFilterButton.kt +++ b/app/src/main/java/com/cornellappdev/score/components/HighlightsFilter.kt @@ -4,11 +4,14 @@ import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement 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 import androidx.compose.foundation.layout.width +import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -22,11 +25,12 @@ import androidx.compose.ui.unit.dp import com.cornellappdev.score.model.Sport import com.cornellappdev.score.theme.GrayStroke import com.cornellappdev.score.theme.Style.bodyNormal +import com.cornellappdev.score.util.sportList @Composable fun HighlightsFilterButton( sport: Sport, - onClick: () -> Unit + onFilterSelected: (Sport) -> Unit ) { Row( modifier = Modifier @@ -39,9 +43,9 @@ fun HighlightsFilterButton( .background(color = Color.White, shape = RoundedCornerShape(100)) .padding(horizontal = 12.dp, vertical = 4.dp) .clip(shape = RoundedCornerShape(100)) - .clickable { onClick }, + .clickable { onFilterSelected }, verticalAlignment = Alignment.CenterVertically, - ) { + ) { Image( painter = painterResource(sport.emptyIcon), contentDescription = "sport Icon" @@ -54,8 +58,32 @@ fun HighlightsFilterButton( } } +@Composable +fun HighlightsFilterRow( + onFilterSelected: (Sport) -> Unit, +) { + LazyRow( + modifier = Modifier + .fillMaxWidth() + .padding(start = 24.dp), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + items(sportList.size) { i -> + HighlightsFilterButton(sportList[i], { onFilterSelected(sportList[i]) }) + Spacer(Modifier.width(12.dp)) + } + } +} + @Preview @Composable private fun HighlightsFilterButtonPreview() { HighlightsFilterButton(Sport.BASEBALL, {}) -} \ No newline at end of file +} + +@Preview +@Composable +private fun HighlightsFilterRowPreview() { + HighlightsFilterRow({}) +} 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 ad94756..4ebb0ff 100644 --- a/app/src/main/java/com/cornellappdev/score/model/Highlights.kt +++ b/app/src/main/java/com/cornellappdev/score/model/Highlights.kt @@ -1,10 +1,17 @@ package com.cornellappdev.score.model -data class HighlightCard( +data class VideoHighlightData( val title: String, val image: String, val url: String, val date: String, val sport: Sport, val gender: GenderDivision +) + +data class ArticleHighlightData( + val title: String, + val image: String, + val url: String, + val date: String ) \ No newline at end of file diff --git a/app/src/main/java/com/cornellappdev/score/screen/HighlightsScreen.kt b/app/src/main/java/com/cornellappdev/score/screen/HighlightsScreen.kt index 4385bc9..3859892 100644 --- a/app/src/main/java/com/cornellappdev/score/screen/HighlightsScreen.kt +++ b/app/src/main/java/com/cornellappdev/score/screen/HighlightsScreen.kt @@ -28,10 +28,12 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.cornellappdev.score.R import com.cornellappdev.score.components.ArticleHighlightCard -import com.cornellappdev.score.components.HighlightsFilterButton +import com.cornellappdev.score.components.EmptyStateBox +import com.cornellappdev.score.components.HighlightsFilterRow import com.cornellappdev.score.components.VideoHighlightCard -import com.cornellappdev.score.model.HighlightCard +import com.cornellappdev.score.model.ArticleHighlightData import com.cornellappdev.score.model.Sport +import com.cornellappdev.score.model.VideoHighlightData import com.cornellappdev.score.theme.GrayLight import com.cornellappdev.score.theme.GrayMedium import com.cornellappdev.score.theme.Style.bodyNormal @@ -41,17 +43,10 @@ import com.cornellappdev.score.util.highlightsList import com.cornellappdev.score.util.sportList @Composable -fun HighlightsScreen( - todayHighlightsList: List, - pastThreeHighlightsList: List, - filtersList: List +fun HighlightsScreenHeader( + onSearch: () -> Unit ) { - Column( - modifier = Modifier - .fillMaxSize() - .background(color = Color.White) - ) { - Spacer(modifier = Modifier.height(24.dp)) + Column(modifier = Modifier.fillMaxWidth()) { Text( modifier = Modifier.padding(start = 24.dp), style = heading1, @@ -65,7 +60,7 @@ fun HighlightsScreen( .background(color = Color.White, shape = RoundedCornerShape(100.dp)) .fillMaxWidth() .clip(shape = RoundedCornerShape(100.dp)) - .clickable {/*todo navigate to search screen*/ }, + .clickable { onSearch }, verticalAlignment = Alignment.CenterVertically ) { Row( @@ -84,19 +79,17 @@ fun HighlightsScreen( } } Spacer(modifier = Modifier.height(16.dp)) - LazyRow( - modifier = Modifier - .fillMaxWidth() - .padding(start = 24.dp), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically - ) { - items(filtersList.size) { i -> - HighlightsFilterButton(filtersList[i], {/*todo filter functionality*/ }) - Spacer(Modifier.width(12.dp)) - } - } - Spacer(modifier = Modifier.height(24.dp)) + HighlightsFilterRow({/*todo on filter selected*/}) + } +} + +@Composable +fun HighlightsCardRow( + highlightsList: List +) { + Column( + modifier = Modifier.fillMaxWidth() + ) { Row( modifier = Modifier .padding(horizontal = 24.dp) @@ -113,7 +106,7 @@ fun HighlightsScreen( verticalAlignment = Alignment.CenterVertically ) { Text( - text = "${todayHighlightsList.size} Results", + text = "${highlightsList.size} Results", style = bodyNormal ) Image( @@ -127,58 +120,74 @@ fun HighlightsScreen( LazyRow( modifier = Modifier.padding(start = 24.dp) ) { - items(todayHighlightsList.size) { i -> - VideoHighlightCard( - todayHighlightsList[i], - false - ) + items(highlightsList.size) { i -> + if (highlightsList[i] is VideoHighlightData) { + VideoHighlightCard( + highlightsList[i] as VideoHighlightData, + false + ) + } else if (highlightsList[i] is ArticleHighlightData) { + ArticleHighlightCard( + highlightsList[i] as ArticleHighlightData, + false + ) + } + Spacer(modifier = Modifier.width(16.dp)) } } Spacer(modifier = Modifier.height(24.dp)) - Row( - modifier = Modifier - .padding(horizontal = 24.dp) - .fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically - ) { - Text( - text = "Past 3 days", - style = heading2 + } +} + +@Composable +fun HighlightsScreen( + todayHighlightsList: List, + pastThreeHighlightsList: List +) { + Column( + modifier = Modifier + .fillMaxSize() + .background(color = Color.White) + ) { + Spacer(modifier = Modifier.height(24.dp)) + HighlightsScreenHeader({}) + Spacer(modifier = Modifier.height(24.dp)) + if (todayHighlightsList.isEmpty() and pastThreeHighlightsList.isEmpty()) { + EmptyStateBox( + icon = R.drawable.kid_star, + title = "No results yet." ) - Row( - modifier = Modifier.clickable {/*todo navigation to Past3Days screen*/ }, - verticalAlignment = Alignment.CenterVertically - ) { - Text( - text = "${pastThreeHighlightsList.size} Results", - style = bodyNormal - ) - Image( - painter = painterResource(R.drawable.ic_right_chevron), - contentDescription = "right chevron", - colorFilter = ColorFilter.tint(GrayMedium, blendMode = BlendMode.SrcIn) - ) - } } - Spacer(modifier = Modifier.height(16.dp)) - LazyRow( - modifier = Modifier.padding(start = 24.dp) - ) { - items(pastThreeHighlightsList.size) { i -> - ArticleHighlightCard( - todayHighlightsList[i], - false - ) - Spacer(modifier = Modifier.width(16.dp)) - } + if (todayHighlightsList.isNotEmpty()) { + HighlightsCardRow(todayHighlightsList) + } + if (pastThreeHighlightsList.isNotEmpty()) { + HighlightsCardRow(pastThreeHighlightsList) } } } +@Composable +@Preview +private fun HighlightsScreenHeaderPreview() { + HighlightsScreenHeader({}) +} + @Composable @Preview private fun HighlightsScreenPreview() { - HighlightsScreen(highlightsList, highlightsList, sportList) + HighlightsScreen(highlightsList, highlightsList) +} + +@Composable +@Preview +private fun EmptyHighlightsScreenPreview() { + HighlightsScreen(emptyList(), emptyList()) +} + +@Composable +@Preview +private fun PartialHighlightsScreenPreview() { + HighlightsScreen(emptyList(), highlightsList) } \ 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 8e046c8..add8a0c 100644 --- a/app/src/main/java/com/cornellappdev/score/util/TestingConstants.kt +++ b/app/src/main/java/com/cornellappdev/score/util/TestingConstants.kt @@ -2,10 +2,11 @@ package com.cornellappdev.score.util import androidx.compose.ui.graphics.Color import com.cornellappdev.score.R +import com.cornellappdev.score.model.ArticleHighlightData import com.cornellappdev.score.model.GameCardData import com.cornellappdev.score.model.GameData import com.cornellappdev.score.model.GenderDivision -import com.cornellappdev.score.model.HighlightCard +import com.cornellappdev.score.model.VideoHighlightData import com.cornellappdev.score.model.ScoreEvent import com.cornellappdev.score.model.Sport import com.cornellappdev.score.model.SportSelection @@ -220,8 +221,9 @@ val sportSelectionList = listOf( SportSelection.SportSelect(Sport.CROSS_COUNTRY), ) +//Mixed type val highlightsList = listOf( - HighlightCard( + VideoHighlightData( "vs Columbia", "maxresdefault.jpg", "https://cornellsun.com/article/london-mcdavid-is-making-a-name-for-herself-at-cornell", @@ -229,15 +231,13 @@ val highlightsList = listOf( Sport.BASEBALL, GenderDivision.MALE ), - HighlightCard( + ArticleHighlightData( "Late Goal Lifts No. 6 Men’s Hockey Over Brown", "maxresdefault.jpg", "https://cornellsun.com/article/london-mcdavid-is-making-a-name-for-herself-at-cornell", - "11/09", - Sport.BASEBALL, - GenderDivision.MALE + "11/09" ), - HighlightCard( + VideoHighlightData( "vs Columbia", "maxresdefault.jpg", "https://cornellsun.com/article/london-mcdavid-is-making-a-name-for-herself-at-cornell", @@ -245,15 +245,13 @@ val highlightsList = listOf( Sport.BASEBALL, GenderDivision.MALE ), - HighlightCard( + ArticleHighlightData( "Late Goal Lifts No. 6 Men’s Hockey Over Brown", "maxresdefault.jpg", "https://cornellsun.com/article/london-mcdavid-is-making-a-name-for-herself-at-cornell", - "11/09", - Sport.BASEBALL, - GenderDivision.MALE + "11/09" ), - HighlightCard( + VideoHighlightData( "vs Columbia", "maxresdefault.jpg", "https://cornellsun.com/article/london-mcdavid-is-making-a-name-for-herself-at-cornell", From 5ed8edd89a84185d70642eef1d5ee28cf8f419ff Mon Sep 17 00:00:00 2001 From: amjiao Date: Fri, 24 Oct 2025 13:17:05 -0400 Subject: [PATCH 07/17] Abstracted EmptyState --- .../cornellappdev/score/components/EmptyState.kt | 6 ++++-- app/src/main/res/drawable/kid_star.xml | 13 +++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 app/src/main/res/drawable/kid_star.xml diff --git a/app/src/main/java/com/cornellappdev/score/components/EmptyState.kt b/app/src/main/java/com/cornellappdev/score/components/EmptyState.kt index 7e440a5..5578446 100644 --- a/app/src/main/java/com/cornellappdev/score/components/EmptyState.kt +++ b/app/src/main/java/com/cornellappdev/score/components/EmptyState.kt @@ -24,6 +24,7 @@ import com.cornellappdev.score.theme.Style.heading2 @Composable fun EmptyState( modifier: Modifier = Modifier, + icon: Int = R.drawable.ic_speaker_gray, title: String = "No games yet.", subtitle: String = "Check back here later!" ) { @@ -33,7 +34,7 @@ fun EmptyState( verticalArrangement = Arrangement.Center ) { Image( - painter = painterResource(R.drawable.ic_speaker_gray), + painter = painterResource(icon), contentDescription = "score speaker icon" ) Spacer(modifier = Modifier.height(16.dp)) @@ -53,6 +54,7 @@ fun EmptyState( fun EmptyStateBox( modifier: Modifier = Modifier, height: Dp = 550.dp, + icon: Int = R.drawable.ic_speaker_gray, title: String = "No games yet.", subtitle: String = "Check back here later!" ) { @@ -61,7 +63,7 @@ fun EmptyStateBox( .height(height) .fillMaxWidth(), contentAlignment = Alignment.Center ) { - EmptyState(title = title, subtitle = subtitle) + EmptyState(icon = icon, title = title, subtitle = subtitle) } } diff --git a/app/src/main/res/drawable/kid_star.xml b/app/src/main/res/drawable/kid_star.xml new file mode 100644 index 0000000..9317f11 --- /dev/null +++ b/app/src/main/res/drawable/kid_star.xml @@ -0,0 +1,13 @@ + + + + + + From b4f48a2f6ec8fbf964b8d9c52f3d814fcd769a8b Mon Sep 17 00:00:00 2001 From: amjiao Date: Sat, 25 Oct 2025 17:38:30 -0400 Subject: [PATCH 08/17] EmptyState.kt improvements + resulting syntax changes in other files --- .../score/components/EmptyState.kt | 68 ++++++++----------- .../score/screen/GameDetailsScreen.kt | 57 +++++++++++++++- .../cornellappdev/score/screen/HomeScreen.kt | 3 +- .../score/screen/PastGamesScreen.kt | 5 +- 4 files changed, 87 insertions(+), 46 deletions(-) diff --git a/app/src/main/java/com/cornellappdev/score/components/EmptyState.kt b/app/src/main/java/com/cornellappdev/score/components/EmptyState.kt index 5578446..837473d 100644 --- a/app/src/main/java/com/cornellappdev/score/components/EmptyState.kt +++ b/app/src/main/java/com/cornellappdev/score/components/EmptyState.kt @@ -1,5 +1,6 @@ package com.cornellappdev.score.components +import androidx.annotation.DrawableRes import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -21,60 +22,45 @@ import com.cornellappdev.score.theme.GrayPrimary import com.cornellappdev.score.theme.Style.bodyNormal import com.cornellappdev.score.theme.Style.heading2 -@Composable -fun EmptyState( - modifier: Modifier = Modifier, - icon: Int = R.drawable.ic_speaker_gray, - title: String = "No games yet.", - subtitle: String = "Check back here later!" -) { - Column( - modifier = modifier, - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Center - ) { - Image( - painter = painterResource(icon), - contentDescription = "score speaker icon" - ) - Spacer(modifier = Modifier.height(16.dp)) - Text( - text = title, - style = heading2.copy(color = GrayPrimary) - ) - Spacer(modifier = Modifier.height(8.dp)) - Text( - text = subtitle, - style = bodyNormal.copy(color = GrayMedium) - ) - } -} - @Composable fun EmptyStateBox( + @DrawableRes icon: Int, + title: String, modifier: Modifier = Modifier, - height: Dp = 550.dp, - icon: Int = R.drawable.ic_speaker_gray, - title: String = "No games yet.", - subtitle: String = "Check back here later!" + subtitle: String = "Check back here later!", + height: Dp = 550.dp //(appx height when full-screen error) ) { Box( modifier = modifier .height(height) .fillMaxWidth(), contentAlignment = Alignment.Center ) { - EmptyState(icon = icon, title = title, subtitle = subtitle) + Column( + modifier = Modifier, + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center + ) { + Image( + painter = painterResource(icon), + contentDescription = "empty state icon" + ) + Spacer(modifier = Modifier.height(16.dp)) + Text( + text = title, + style = heading2.copy(color = GrayPrimary) + ) + Spacer(modifier = Modifier.height(8.dp)) + Text( + text = subtitle, + style = bodyNormal.copy(color = GrayMedium) + ) + } } } -@Preview -@Composable -private fun EmptyStatePreview() = ScorePreview { - EmptyState() -} @Preview @Composable private fun EmptyStateBoxPreview() = ScorePreview { - EmptyStateBox() -} \ No newline at end of file + EmptyStateBox(R.drawable.ic_speaker_gray, "No games yet.") +} 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 4062de6..001f500 100644 --- a/app/src/main/java/com/cornellappdev/score/screen/GameDetailsScreen.kt +++ b/app/src/main/java/com/cornellappdev/score/screen/GameDetailsScreen.kt @@ -198,7 +198,11 @@ fun GameDetailsContent( Spacer(modifier = Modifier.height(16.dp)) ScoringSummary(gameCard.scoreEvent) } else { - EmptyStateBox(height = 200.dp, title = "No scores yet.") + EmptyStateBox( + icon = R.drawable.ic_speaker_gray, + title = "No scores yet.", + height = 200.dp + ) } } else { val context = LocalContext.current @@ -331,3 +335,54 @@ private fun GameDetailsPreview() { ), navigateToGameScoreSummary = {} ) } + +@Preview +@Composable +private fun EmptyGameDetailsPreview() { + GameDetailsContent( + DetailsCardData( + title = "Championship Game", + opponentLogo = "https://example.com/logo.png", + opponent = "Wildcats", + opponentColor = Color(0xFF123456), + date = LocalDate.of(2025, 4, 20), + time = "7:30 PM", + dateString = "April 20, 2025", + isPastStartTime = true, + location = "Main Stadium", + locationString = "Main Stadium, Cityville", + gender = "Men's", + genderIcon = 123, // Dummy resource ID + sport = "Basketball", + sportIcon = 456, // Dummy resource ID + boxScore = emptyList(), + scoreBreakdown = listOf( + emptyList(), + emptyList() + ), + gameData = GameData( + Pair( + TeamScore( + team = TeamBoxScore( + name = "Tigers", + ), + scoresByPeriod = emptyList(), + totalScore = 0 + ), + TeamScore( + team = TeamBoxScore( + name = "Wildcats", + ), + scoresByPeriod = emptyList(), + totalScore = 0 + ) + ) + ), + scoreEvent = emptyList(), + daysUntilGame = 0, + hoursUntilGame = 0, + homeScore = 0, + oppScore = 0 + ), navigateToGameScoreSummary = {} + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/cornellappdev/score/screen/HomeScreen.kt b/app/src/main/java/com/cornellappdev/score/screen/HomeScreen.kt index 9e42a06..3145dfc 100644 --- a/app/src/main/java/com/cornellappdev/score/screen/HomeScreen.kt +++ b/app/src/main/java/com/cornellappdev/score/screen/HomeScreen.kt @@ -24,6 +24,7 @@ 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.cornellappdev.score.R import com.cornellappdev.score.components.EmptyStateBox import com.cornellappdev.score.components.ErrorState import com.cornellappdev.score.components.GameCard @@ -175,7 +176,7 @@ private fun HomeLazyColumn( } } else { item { - EmptyStateBox() + EmptyStateBox(icon = R.drawable.ic_speaker_gray, title = "No games yet.") } } } diff --git a/app/src/main/java/com/cornellappdev/score/screen/PastGamesScreen.kt b/app/src/main/java/com/cornellappdev/score/screen/PastGamesScreen.kt index ce4014f..8cd7f11 100644 --- a/app/src/main/java/com/cornellappdev/score/screen/PastGamesScreen.kt +++ b/app/src/main/java/com/cornellappdev/score/screen/PastGamesScreen.kt @@ -7,7 +7,6 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding @@ -22,7 +21,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel -import com.cornellappdev.score.components.EmptyState +import com.cornellappdev.score.R import com.cornellappdev.score.components.EmptyStateBox import com.cornellappdev.score.components.ErrorState import com.cornellappdev.score.components.GamesCarousel @@ -167,7 +166,7 @@ private fun PastGamesLazyColumn( } } else { item { - EmptyStateBox() + EmptyStateBox(icon = R.drawable.ic_speaker_gray, title = "No games yet.") } } } From f20dda3d868ed502ea89c450c4e0f767cd947c63 Mon Sep 17 00:00:00 2001 From: amjiao Date: Tue, 28 Oct 2025 01:24:19 -0400 Subject: [PATCH 09/17] Address highlights card comments --- .../score/components/HighlightsCard.kt | 327 ------------------ .../highlights/ArticleHighlightsCard.kt | 144 ++++++++ .../{ => highlights}/HighlightsFilter.kt | 2 +- .../highlights/VideoHighlightsCard.kt | 202 +++++++++++ .../score/screen/HighlightsScreen.kt | 8 +- 5 files changed, 350 insertions(+), 333 deletions(-) delete mode 100644 app/src/main/java/com/cornellappdev/score/components/HighlightsCard.kt create mode 100644 app/src/main/java/com/cornellappdev/score/components/highlights/ArticleHighlightsCard.kt rename app/src/main/java/com/cornellappdev/score/components/{ => highlights}/HighlightsFilter.kt (98%) create mode 100644 app/src/main/java/com/cornellappdev/score/components/highlights/VideoHighlightsCard.kt diff --git a/app/src/main/java/com/cornellappdev/score/components/HighlightsCard.kt b/app/src/main/java/com/cornellappdev/score/components/HighlightsCard.kt deleted file mode 100644 index 7e11e8f..0000000 --- a/app/src/main/java/com/cornellappdev/score/components/HighlightsCard.kt +++ /dev/null @@ -1,327 +0,0 @@ -package com.cornellappdev.score.components - -import androidx.compose.foundation.Image -import androidx.compose.foundation.background -import androidx.compose.foundation.border -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -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.foundation.text.BasicText -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.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.GenderDivision -import com.cornellappdev.score.model.VideoHighlightData -import com.cornellappdev.score.model.Sport -import com.cornellappdev.score.theme.CrimsonPrimary -import com.cornellappdev.score.theme.GrayStroke -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 - -@Composable -fun VideoHighlightCardHeader( - image: String -) { - Box( - modifier = Modifier - .fillMaxWidth() - .height(117.dp) - .clip(RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp)) - ) { - AsyncImage( - model = image, - contentDescription = "Highlight article image" - ) - Box( - modifier = Modifier - .fillMaxSize() - .background(color = Color.Black.copy(alpha = 0.4f)) - ) - } -} - -@Composable -fun VideoHighlightCard( - videoHighlight: VideoHighlightData, - wide: Boolean, - modifier: Modifier = Modifier -) { - Column( - modifier = if (wide) modifier.fillMaxWidth() else modifier.width(241.dp) - ) { - VideoHighlightCardHeader(videoHighlight.image) - - Column( - modifier = Modifier - .height(75.dp) - .clip(RoundedCornerShape(bottomStart = 12.dp, bottomEnd = 12.dp)) - .background(color = Color.White) - .border( - width = 1.dp, - color = GrayStroke, - shape = RoundedCornerShape(bottomStart = 12.dp, bottomEnd = 12.dp) - ) - .padding(horizontal = 16.dp, vertical = 8.dp), - ) { - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically - ) { - Text( - modifier = Modifier.weight(1f), - style = heading2, - text = videoHighlight.title, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - Row( - verticalAlignment = Alignment.CenterVertically - ) { - Image( - painter = painterResource(videoHighlight.sport.emptyIcon), - contentDescription = "Sport icon", - modifier = Modifier - .width(24.dp) - .height(24.dp) - ) - Image( - painter = painterResource(if (videoHighlight.gender == GenderDivision.FEMALE) R.drawable.ic_gender_women else R.drawable.ic_gender_men), - contentDescription = "Gender icon" - ) - } - } - Spacer(Modifier.height(8.dp)) - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically - ) { - Row( - verticalAlignment = Alignment.CenterVertically - ) { - BasicText( - text = buildAnnotatedString { - withLink( - LinkAnnotation.Url( - videoHighlight.url, - TextLinkStyles( - style = SpanStyle( - textDecoration = TextDecoration.Underline, - color = CrimsonPrimary - ) - ), - ) - ) { - append("YouTube") - } - } - ) - Image( - painter = painterResource(R.drawable.arrow_outward_red), - contentDescription = "external link arrow" - ) - } - Text( - style = labelsNormal, - text = "11/09" - ) - } - } - } -} - -@Composable -fun ArticleHighlightCard( - articleHighlight: ArticleHighlightData, - wide: Boolean, - modifier: Modifier = Modifier -) { - Box( - modifier = modifier.then( - if (wide) Modifier.fillMaxWidth() else Modifier.width(241.dp) - ) - .height(192.dp) - .clip(shape = RoundedCornerShape(12.dp)) - ) { - AsyncImage( - model = articleHighlight.image, - contentDescription = "highlight image" - ) - Box( - modifier = Modifier - .fillMaxSize() - .background(color = Color.Black.copy(alpha = 0.4f)) - - ) - Column( - modifier = Modifier - .fillMaxSize() - .padding(12.dp), - verticalArrangement = Arrangement.SpaceBetween - ) { - Text( - style = heading2, - color = Color.White, - text = articleHighlight.title, - maxLines = 4, - overflow = TextOverflow.Ellipsis - ) - - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically - ) { - Row( - verticalAlignment = Alignment.CenterVertically - ) { - BasicText( - style = bodySemibold, - text = buildAnnotatedString { - withLink( - LinkAnnotation.Url( - articleHighlight.url, - TextLinkStyles( - style = SpanStyle( - textDecoration = TextDecoration.Underline, - color = White - ) - ), - ) - ) { - append("Cornell Daily Sun") - } - } - ) - Image( - painter = painterResource(R.drawable.arrow_outward_white), - contentDescription = "external link arrow" - ) - } - Text( - color = Color.White, - style = labelsNormal, - text = "11/09" - ) - } - } - } -} - -@Preview -@Composable -private fun ArticleHighlightCardPreview() { - ArticleHighlightCard( - ArticleHighlightData( - "Late Goal Lifts No. 6 Men’s Hockey Over Brown", - "maxresdefault.jpg", - "https://cornellsun.com/article/london-mcdavid-is-making-a-name-for-herself-at-cornell", - "11/9" - ), - false - ) -} -@Preview -@Composable -private fun WideArticleHighlightCardPreview() { - ArticleHighlightCard( - ArticleHighlightData( - "Late Goal Lifts No. 6 Men’s Hockey Over Brown", - "maxresdefault.jpg", - "https://cornellsun.com/article/london-mcdavid-is-making-a-name-for-herself-at-cornell", - "11/9" - ), - true - ) -} - -@Preview -@Composable -private fun VideoHighlightCardPreview() { - VideoHighlightCard( - VideoHighlightData( - "vs Columbia", - "maxresdefault.jpg", - "https://cornellsun.com/article/london-mcdavid-is-making-a-name-for-herself-at-cornell", - "11/9", - Sport.BASEBALL, - GenderDivision.MALE - ), - false - ) -} - -@Preview -@Composable -private fun WideVideoHighlightCardPreview() { - VideoHighlightCard( - VideoHighlightData( - "vs Columbia", - "maxresdefault.jpg", - "https://cornellsun.com/article/london-mcdavid-is-making-a-name-for-herself-at-cornell", - "11/9", - Sport.BASEBALL, - GenderDivision.MALE - ), - true - ) -} - -@Preview -@Composable -private fun OverflowVideoHighlightCardPreview() { - VideoHighlightCard( - VideoHighlightData( - "Late Goal Lifts No. 6 Men’s Hockey Over Brown", - "maxresdefault.jpg", - "https://cornellsun.com/article/london-mcdavid-is-making-a-name-for-herself-at-cornell", - "11/9", - Sport.BASEBALL, - GenderDivision.MALE - ), - false - ) -} - -@Preview -@Composable -private fun WideOverflowVideoHighlightCardPreview() { - VideoHighlightCard( - VideoHighlightData( - "Late Goal Lifts No. 6 Men’s Hockey Over Brown", - "maxresdefault.jpg", - "https://cornellsun.com/article/london-mcdavid-is-making-a-name-for-herself-at-cornell", - "11/9", - Sport.BASEBALL, - GenderDivision.MALE - ), - true - ) -} \ No newline at end of file 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 new file mode 100644 index 0000000..c44fc37 --- /dev/null +++ b/app/src/main/java/com/cornellappdev/score/components/highlights/ArticleHighlightsCard.kt @@ -0,0 +1,144 @@ +package com.cornellappdev.score.components.highlights + +import androidx.compose.foundation.Image +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.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.shape.RoundedCornerShape +import androidx.compose.foundation.text.BasicText +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.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.theme.Style.bodySemibold +import com.cornellappdev.score.theme.Style.heading2 +import com.cornellappdev.score.theme.Style.labelsNormal +import com.cornellappdev.score.theme.White + +@Composable +fun ArticleHighlightCard( + articleHighlight: ArticleHighlightData, + wide: Boolean, + modifier: Modifier = Modifier +) { + Box( + modifier = modifier + .then( + if (wide) Modifier.fillMaxWidth() else Modifier.width(241.dp) + ) + .height(192.dp) + .clip(shape = RoundedCornerShape(12.dp)) + ) { + AsyncImage( + model = articleHighlight.image, + contentDescription = "highlight image" + ) + Box( + modifier = Modifier + .fillMaxSize() + .background(color = Color.Black.copy(alpha = 0.4f)) + ) + Column( + modifier = Modifier + .fillMaxSize() + .padding(12.dp), + verticalArrangement = Arrangement.SpaceBetween + ) { + Text( + style = heading2, + color = Color.White, + text = articleHighlight.title, + maxLines = 4, + overflow = TextOverflow.Ellipsis + ) + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Row( + verticalAlignment = Alignment.CenterVertically + ) { + BasicText( + style = bodySemibold, + text = buildAnnotatedString { + withLink( + LinkAnnotation.Url( + articleHighlight.url, + TextLinkStyles( + style = SpanStyle( + textDecoration = TextDecoration.Underline, + color = White + ) + ), + ) + ) { + append("Cornell Daily Sun") + } + } + ) + Image( + painter = painterResource(R.drawable.arrow_outward_white), + contentDescription = "external link arrow" + ) + } + Text( + color = Color.White, + style = labelsNormal, + text = articleHighlight.date + ) + } + } + } +} + +@Preview +@Composable +private fun ArticleHighlightCardPreview() { + ArticleHighlightCard( + ArticleHighlightData( + "Late Goal Lifts No. 6 Men’s Hockey Over Brown", + "maxresdefault.jpg", + "https://cornellsun.com/article/london-mcdavid-is-making-a-name-for-herself-at-cornell", + "11/9" + ), + false + ) +} + +@Preview +@Composable +private fun WideArticleHighlightCardPreview() { + ArticleHighlightCard( + ArticleHighlightData( + "Late Goal Lifts No. 6 Men’s Hockey Over Brown", + "maxresdefault.jpg", + "https://cornellsun.com/article/london-mcdavid-is-making-a-name-for-herself-at-cornell", + "11/9" + ), + true + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/cornellappdev/score/components/HighlightsFilter.kt b/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsFilter.kt similarity index 98% rename from app/src/main/java/com/cornellappdev/score/components/HighlightsFilter.kt rename to app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsFilter.kt index 1eb9e4f..47c9735 100644 --- a/app/src/main/java/com/cornellappdev/score/components/HighlightsFilter.kt +++ b/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsFilter.kt @@ -1,4 +1,4 @@ -package com.cornellappdev.score.components +package com.cornellappdev.score.components.highlights import androidx.compose.foundation.Image import androidx.compose.foundation.background diff --git a/app/src/main/java/com/cornellappdev/score/components/highlights/VideoHighlightsCard.kt b/app/src/main/java/com/cornellappdev/score/components/highlights/VideoHighlightsCard.kt new file mode 100644 index 0000000..bb84f34 --- /dev/null +++ b/app/src/main/java/com/cornellappdev/score/components/highlights/VideoHighlightsCard.kt @@ -0,0 +1,202 @@ +package com.cornellappdev.score.components.highlights + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +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.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.BasicText +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.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.tooling.preview.PreviewParameter +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import androidx.compose.ui.unit.dp +import coil3.compose.AsyncImage +import com.cornellappdev.score.R +import com.cornellappdev.score.components.ScorePreview +import com.cornellappdev.score.model.GenderDivision +import com.cornellappdev.score.model.Sport +import com.cornellappdev.score.model.VideoHighlightData +import com.cornellappdev.score.theme.CrimsonPrimary +import com.cornellappdev.score.theme.GrayStroke +import com.cornellappdev.score.theme.Style.heading2 +import com.cornellappdev.score.theme.Style.labelsNormal + +@Composable +private fun VideoHighlightCardHeader( + imageUrl: String +) { + Box( + modifier = Modifier + .fillMaxWidth() + .height(117.dp) + ) { + AsyncImage( + model = imageUrl, + contentDescription = "Highlight article image" + ) + Box( + modifier = Modifier + .fillMaxSize() + .background(color = Color.Black.copy(alpha = 0.4f)) + ) + } +} + +@Composable +fun VideoHighlightCard( + videoHighlight: VideoHighlightData, + wide: Boolean, + modifier: Modifier = Modifier +) { + Column( + modifier = if (wide) modifier.fillMaxWidth() else modifier + .width(241.dp) + .clip(RoundedCornerShape(16.dp)) + ) { + VideoHighlightCardHeader(videoHighlight.image) + + Column( + modifier = Modifier + .height(75.dp) + .background(color = Color.White) + .border( + width = 1.dp, + color = GrayStroke, + shape = RoundedCornerShape(bottomStart = 12.dp, bottomEnd = 12.dp) + ) + .padding(horizontal = 16.dp, vertical = 8.dp), + ) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + modifier = Modifier.weight(1f), + style = heading2, + text = videoHighlight.title, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Image( + painter = painterResource(videoHighlight.sport.emptyIcon), + contentDescription = "Sport icon", + modifier = Modifier.size(24.dp) + ) + Image( + painter = painterResource(if (videoHighlight.gender == GenderDivision.FEMALE) R.drawable.ic_gender_women else R.drawable.ic_gender_men), + contentDescription = "Gender icon" + ) + } + } + Spacer(Modifier.height(8.dp)) + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Row( + verticalAlignment = Alignment.CenterVertically + ) { + BasicText( + text = buildAnnotatedString { + withLink( + LinkAnnotation.Url( + videoHighlight.url, + TextLinkStyles( + style = SpanStyle( + textDecoration = TextDecoration.Underline, + color = CrimsonPrimary + ) + ), + ) + ) { + append("YouTube") + } + } + ) + Image( + painter = painterResource(R.drawable.arrow_outward_red), + contentDescription = "external link arrow" + ) + } + Text( + style = labelsNormal, + text = videoHighlight.date + ) + } + } + } +} + +data class VideoHighlightPreviewData( + val videoHighlight: VideoHighlightData, + val wide: Boolean +) + +class VideoHighlightsPreviewProvider : PreviewParameterProvider { + override val values: Sequence = sequence { + val samples = listOf( + VideoHighlightData( + "vs Columbia", + "maxresdefault.jpg", + "https://cornellsun.com/article/london-mcdavid-is-making-a-name-for-herself-at-cornell", + "11/9", + Sport.BASEBALL, + GenderDivision.MALE + ), + VideoHighlightData( + "Late Goal Lifts No. 6 Men’s Hockey Over Brown", + "maxresdefault.jpg", + "https://cornellsun.com/article/london-mcdavid-is-making-a-name-for-herself-at-cornell", + "11/9", + Sport.BASEBALL, + GenderDivision.MALE + ) + ) + for (sample in samples) { + yield(VideoHighlightPreviewData(sample, wide = true)) + yield(VideoHighlightPreviewData(sample, wide = false)) + } + } +} + +@Preview(showBackground = true) +@Composable +private fun VideoHighlightCardPreview( + @PreviewParameter(VideoHighlightsPreviewProvider::class) previewData: VideoHighlightPreviewData +) { + ScorePreview { + VideoHighlightCard( + videoHighlight = previewData.videoHighlight, + wide = previewData.wide + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/cornellappdev/score/screen/HighlightsScreen.kt b/app/src/main/java/com/cornellappdev/score/screen/HighlightsScreen.kt index 3859892..f0e035f 100644 --- a/app/src/main/java/com/cornellappdev/score/screen/HighlightsScreen.kt +++ b/app/src/main/java/com/cornellappdev/score/screen/HighlightsScreen.kt @@ -27,12 +27,11 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.cornellappdev.score.R -import com.cornellappdev.score.components.ArticleHighlightCard +import com.cornellappdev.score.components.highlights.ArticleHighlightCard import com.cornellappdev.score.components.EmptyStateBox -import com.cornellappdev.score.components.HighlightsFilterRow -import com.cornellappdev.score.components.VideoHighlightCard +import com.cornellappdev.score.components.highlights.HighlightsFilterRow +import com.cornellappdev.score.components.highlights.VideoHighlightCard import com.cornellappdev.score.model.ArticleHighlightData -import com.cornellappdev.score.model.Sport import com.cornellappdev.score.model.VideoHighlightData import com.cornellappdev.score.theme.GrayLight import com.cornellappdev.score.theme.GrayMedium @@ -40,7 +39,6 @@ import com.cornellappdev.score.theme.Style.bodyNormal import com.cornellappdev.score.theme.Style.heading1 import com.cornellappdev.score.theme.Style.heading2 import com.cornellappdev.score.util.highlightsList -import com.cornellappdev.score.util.sportList @Composable fun HighlightsScreenHeader( From bfe40c2e1fab12bd7ba9878f6f82587278d140a6 Mon Sep 17 00:00:00 2001 From: amjiao Date: Wed, 29 Oct 2025 11:19:51 -0400 Subject: [PATCH 10/17] Fixes to highlight cards --- .../highlights/ArticleHighlightsCard.kt | 25 ++- .../highlights/VideoHighlightsCard.kt | 162 ++++++++++-------- 2 files changed, 98 insertions(+), 89 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 c44fc37..6c09527 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 @@ -1,6 +1,5 @@ package com.cornellappdev.score.components.highlights -import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -13,12 +12,14 @@ 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 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 @@ -40,20 +41,19 @@ import com.cornellappdev.score.theme.White @Composable fun ArticleHighlightCard( articleHighlight: ArticleHighlightData, - wide: Boolean, - modifier: Modifier = Modifier + modifier: Modifier = Modifier //for wide cards, specify Modifier.fillMaxWidth() ) { Box( modifier = modifier - .then( - if (wide) Modifier.fillMaxWidth() else Modifier.width(241.dp) - ) + .width(241.dp) .height(192.dp) .clip(shape = RoundedCornerShape(12.dp)) ) { + //todo: empty state if image doesn't load AsyncImage( - model = articleHighlight.image, - contentDescription = "highlight image" + model = articleHighlight.imageUrl, + contentDescription = "highlight image", + contentScale = ContentScale.Crop ) Box( modifier = Modifier @@ -87,7 +87,7 @@ fun ArticleHighlightCard( text = buildAnnotatedString { withLink( LinkAnnotation.Url( - articleHighlight.url, + articleHighlight.articleUrl, TextLinkStyles( style = SpanStyle( textDecoration = TextDecoration.Underline, @@ -100,7 +100,7 @@ fun ArticleHighlightCard( } } ) - Image( + Icon( painter = painterResource(R.drawable.arrow_outward_white), contentDescription = "external link arrow" ) @@ -124,8 +124,7 @@ private fun ArticleHighlightCardPreview() { "maxresdefault.jpg", "https://cornellsun.com/article/london-mcdavid-is-making-a-name-for-herself-at-cornell", "11/9" - ), - false + ) ) } @@ -139,6 +138,6 @@ private fun WideArticleHighlightCardPreview() { "https://cornellsun.com/article/london-mcdavid-is-making-a-name-for-herself-at-cornell", "11/9" ), - true + Modifier.fillMaxWidth() ) } \ No newline at end of file diff --git a/app/src/main/java/com/cornellappdev/score/components/highlights/VideoHighlightsCard.kt b/app/src/main/java/com/cornellappdev/score/components/highlights/VideoHighlightsCard.kt index bb84f34..f92579f 100644 --- a/app/src/main/java/com/cornellappdev/score/components/highlights/VideoHighlightsCard.kt +++ b/app/src/main/java/com/cornellappdev/score/components/highlights/VideoHighlightsCard.kt @@ -1,6 +1,5 @@ package com.cornellappdev.score.components.highlights -import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.layout.Arrangement @@ -16,12 +15,14 @@ import androidx.compose.foundation.layout.size 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 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 @@ -54,9 +55,11 @@ private fun VideoHighlightCardHeader( .fillMaxWidth() .height(117.dp) ) { + //todo: empty state if image doesn't load AsyncImage( model = imageUrl, - contentDescription = "Highlight article image" + contentDescription = "Highlight article image", + contentScale = ContentScale.Crop ) Box( modifier = Modifier @@ -67,98 +70,105 @@ private fun VideoHighlightCardHeader( } @Composable -fun VideoHighlightCard( - videoHighlight: VideoHighlightData, - wide: Boolean, - modifier: Modifier = Modifier +fun VideoHighlightCardBody( + videoHighlight: VideoHighlightData ) { Column( - modifier = if (wide) modifier.fillMaxWidth() else modifier - .width(241.dp) - .clip(RoundedCornerShape(16.dp)) + modifier = Modifier + .fillMaxWidth() + .height(75.dp) + .background(color = Color.White) + .border( + width = 1.dp, + color = GrayStroke, + shape = RoundedCornerShape(bottomStart = 12.dp, bottomEnd = 12.dp) + ) + .padding(horizontal = 16.dp, vertical = 8.dp), ) { - VideoHighlightCardHeader(videoHighlight.image) - - Column( - modifier = Modifier - .height(75.dp) - .background(color = Color.White) - .border( - width = 1.dp, - color = GrayStroke, - shape = RoundedCornerShape(bottomStart = 12.dp, bottomEnd = 12.dp) - ) - .padding(horizontal = 16.dp, vertical = 8.dp), + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically ) { + Text( + modifier = Modifier.weight(1f), + style = heading2, + text = videoHighlight.title, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically ) { - Text( - modifier = Modifier.weight(1f), - style = heading2, - text = videoHighlight.title, - maxLines = 1, - overflow = TextOverflow.Ellipsis + Icon( + painter = painterResource(videoHighlight.sport.emptyIcon), + contentDescription = "Sport icon", + modifier = Modifier.size(24.dp) + ) + Icon( + painter = painterResource(if (videoHighlight.gender == GenderDivision.FEMALE) R.drawable.ic_gender_women else R.drawable.ic_gender_men), + contentDescription = "Gender icon" ) - Row( - verticalAlignment = Alignment.CenterVertically - ) { - Image( - painter = painterResource(videoHighlight.sport.emptyIcon), - contentDescription = "Sport icon", - modifier = Modifier.size(24.dp) - ) - Image( - painter = painterResource(if (videoHighlight.gender == GenderDivision.FEMALE) R.drawable.ic_gender_women else R.drawable.ic_gender_men), - contentDescription = "Gender icon" - ) - } } - Spacer(Modifier.height(8.dp)) + } + Spacer(Modifier.height(8.dp)) + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically ) { - Row( - verticalAlignment = Alignment.CenterVertically - ) { - BasicText( - text = buildAnnotatedString { - withLink( - LinkAnnotation.Url( - videoHighlight.url, - TextLinkStyles( - style = SpanStyle( - textDecoration = TextDecoration.Underline, - color = CrimsonPrimary - ) - ), - ) - ) { - append("YouTube") - } + BasicText( + text = buildAnnotatedString { + withLink( + LinkAnnotation.Url( + videoHighlight.videoUrl, + TextLinkStyles( + style = SpanStyle( + textDecoration = TextDecoration.Underline, + color = CrimsonPrimary + ) + ), + ) + ) { + append("YouTube") } - ) - Image( - painter = painterResource(R.drawable.arrow_outward_red), - contentDescription = "external link arrow" - ) - } - Text( - style = labelsNormal, - text = videoHighlight.date + } + ) + Icon( + painter = painterResource(R.drawable.arrow_outward_red), + contentDescription = "external link arrow" ) } + Text( + style = labelsNormal, + text = videoHighlight.date + ) } } } +@Composable +fun VideoHighlightCard( + videoHighlight: VideoHighlightData, + modifier: Modifier = Modifier //for wide cards, specify Modifier.fillMaxWidth() +) { + Column( + modifier = modifier + .width(241.dp) + .clip(RoundedCornerShape(16.dp)) + ) { + VideoHighlightCardHeader(videoHighlight.thumbnailImageUrl) + + VideoHighlightCardBody(videoHighlight) + } +} + data class VideoHighlightPreviewData( val videoHighlight: VideoHighlightData, - val wide: Boolean + val modifier: Modifier ) class VideoHighlightsPreviewProvider : PreviewParameterProvider { @@ -182,8 +192,8 @@ class VideoHighlightsPreviewProvider : PreviewParameterProvider Date: Wed, 29 Oct 2025 13:41:59 -0400 Subject: [PATCH 11/17] Fixed SportSelectorHeader scroll appearance --- .../score/components/SportSelectorHeader.kt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/cornellappdev/score/components/SportSelectorHeader.kt b/app/src/main/java/com/cornellappdev/score/components/SportSelectorHeader.kt index 313ccd9..2f4e7d7 100644 --- a/app/src/main/java/com/cornellappdev/score/components/SportSelectorHeader.kt +++ b/app/src/main/java/com/cornellappdev/score/components/SportSelectorHeader.kt @@ -78,7 +78,11 @@ fun SportSelectorHeader( } } Spacer(Modifier.height(24.dp)) - LazyRow(Modifier.fillMaxWidth()) { + LazyRow( + Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(20.dp) + ) { + item { Spacer(Modifier.width(4.dp)) } items(sports) { selection -> when (selection) { SportSelection.All -> { @@ -108,9 +112,6 @@ fun SportSelectorHeader( } } } - - - Spacer(modifier = Modifier.width(20.dp)) } item { Spacer(modifier = Modifier.width(4.dp)) } } From f60d60bf8c0b3d022cf2ced09d0760b11bacc948 Mon Sep 17 00:00:00 2001 From: amjiao Date: Mon, 3 Nov 2025 11:18:32 -0500 Subject: [PATCH 12/17] Highlights Card Fixes --- .../highlights/ArticleHighlightsCard.kt | 10 ++- .../highlights/HighlightsCardRow.kt | 87 +++++++++++++++++++ .../highlights/VideoHighlightsCard.kt | 11 ++- .../cornellappdev/score/model/Highlights.kt | 18 ++-- 4 files changed, 113 insertions(+), 13 deletions(-) create mode 100644 app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsCardRow.kt 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 6c09527..352fa0c 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 @@ -33,6 +33,7 @@ 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 @@ -102,7 +103,8 @@ fun ArticleHighlightCard( ) Icon( painter = painterResource(R.drawable.arrow_outward_white), - contentDescription = "external link arrow" + contentDescription = "external link arrow", + tint = Color.Unspecified ) } Text( @@ -123,7 +125,8 @@ private fun ArticleHighlightCardPreview() { "Late Goal Lifts No. 6 Men’s Hockey Over Brown", "maxresdefault.jpg", "https://cornellsun.com/article/london-mcdavid-is-making-a-name-for-herself-at-cornell", - "11/9" + "11/9", + Sport.ICE_HOCKEY ) ) } @@ -136,7 +139,8 @@ private fun WideArticleHighlightCardPreview() { "Late Goal Lifts No. 6 Men’s Hockey Over Brown", "maxresdefault.jpg", "https://cornellsun.com/article/london-mcdavid-is-making-a-name-for-herself-at-cornell", - "11/9" + "11/9", + Sport.ICE_HOCKEY ), Modifier.fillMaxWidth() ) diff --git a/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsCardRow.kt b/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsCardRow.kt new file mode 100644 index 0000000..107906e --- /dev/null +++ b/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsCardRow.kt @@ -0,0 +1,87 @@ +package com.cornellappdev.score.components.highlights + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +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 +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.lazy.items +import androidx.compose.material3.Icon +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.cornellappdev.score.R +import com.cornellappdev.score.components.ScorePreview +import com.cornellappdev.score.model.HighlightData +import com.cornellappdev.score.theme.Style.bodyNormal +import com.cornellappdev.score.theme.Style.heading2 +import com.cornellappdev.score.util.highlightsList + +@Composable +fun HighlightsCardRow( + highlightsList: List, + rowHeader: String +) { + Column( + modifier = Modifier.fillMaxWidth() + ) { + Row( + modifier = Modifier + .padding(horizontal = 24.dp) + .fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = rowHeader, + style = heading2 + ) + Row( + modifier = Modifier.clickable {/*todo navigation to Today screen*/ }, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "${highlightsList.size} Results", + style = bodyNormal + ) + Icon( + painter = painterResource(R.drawable.ic_right_chevron_small), + contentDescription = "right chevron", + tint = Color.Unspecified + ) + } + } + Spacer(modifier = Modifier.height(16.dp)) + LazyRow( + horizontalArrangement = Arrangement.spacedBy(16.dp) + ) { + item { Spacer(Modifier.width(8.dp)) } + items(highlightsList) { item -> + when (item) { + is HighlightData.Video -> VideoHighlightCard(item.data) + is HighlightData.Article -> ArticleHighlightCard(item.data) + } + } + item { Spacer(Modifier.width(8.dp)) } + } + Spacer(modifier = Modifier.height(24.dp)) + } +} + +@Preview +@Composable +private fun HighlightsCardRowPreview() { + ScorePreview { + HighlightsCardRow(highlightsList, "Today") + } +} diff --git a/app/src/main/java/com/cornellappdev/score/components/highlights/VideoHighlightsCard.kt b/app/src/main/java/com/cornellappdev/score/components/highlights/VideoHighlightsCard.kt index f92579f..e7921b1 100644 --- a/app/src/main/java/com/cornellappdev/score/components/highlights/VideoHighlightsCard.kt +++ b/app/src/main/java/com/cornellappdev/score/components/highlights/VideoHighlightsCard.kt @@ -103,11 +103,13 @@ fun VideoHighlightCardBody( Icon( painter = painterResource(videoHighlight.sport.emptyIcon), contentDescription = "Sport icon", - modifier = Modifier.size(24.dp) + modifier = Modifier.size(24.dp), + tint = Color.Unspecified ) Icon( painter = painterResource(if (videoHighlight.gender == GenderDivision.FEMALE) R.drawable.ic_gender_women else R.drawable.ic_gender_men), - contentDescription = "Gender icon" + contentDescription = "Gender icon", + tint = Color.Unspecified ) } } @@ -139,7 +141,8 @@ fun VideoHighlightCardBody( ) Icon( painter = painterResource(R.drawable.arrow_outward_red), - contentDescription = "external link arrow" + contentDescription = "external link arrow", + tint = Color.Unspecified ) } Text( @@ -158,7 +161,7 @@ fun VideoHighlightCard( Column( modifier = modifier .width(241.dp) - .clip(RoundedCornerShape(16.dp)) + .clip(RoundedCornerShape(12.dp)) ) { VideoHighlightCardHeader(videoHighlight.thumbnailImageUrl) 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 4ebb0ff..df339b6 100644 --- a/app/src/main/java/com/cornellappdev/score/model/Highlights.kt +++ b/app/src/main/java/com/cornellappdev/score/model/Highlights.kt @@ -2,8 +2,8 @@ package com.cornellappdev.score.model data class VideoHighlightData( val title: String, - val image: String, - val url: String, + val thumbnailImageUrl: String, + val videoUrl: String, val date: String, val sport: Sport, val gender: GenderDivision @@ -11,7 +11,13 @@ data class VideoHighlightData( data class ArticleHighlightData( val title: String, - val image: String, - val url: String, - val date: String -) \ No newline at end of file + val imageUrl: String, + val articleUrl: String, + val date: String, + val sport: Sport +) + +sealed class HighlightData { + data class Video(val data: VideoHighlightData) : HighlightData() + data class Article(val data: ArticleHighlightData) : HighlightData() +} \ No newline at end of file From 83c08e75134cbdb65a27e5aaa5964fb260f6c661 Mon Sep 17 00:00:00 2001 From: amjiao Date: Mon, 3 Nov 2025 11:18:45 -0500 Subject: [PATCH 13/17] HighlightsFilter fixes --- .../components/highlights/HighlightsFilter.kt | 73 +++++++++++-------- 1 file changed, 41 insertions(+), 32 deletions(-) diff --git a/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsFilter.kt b/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsFilter.kt index 47c9735..ea273ff 100644 --- a/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsFilter.kt +++ b/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsFilter.kt @@ -1,54 +1,61 @@ package com.cornellappdev.score.components.highlights -import androidx.compose.foundation.Image -import androidx.compose.foundation.background -import androidx.compose.foundation.border -import androidx.compose.foundation.clickable + +import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Spacer 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.lazy.LazyRow +import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.ButtonDefaults.outlinedButtonColors +import androidx.compose.material3.Icon +import androidx.compose.material3.OutlinedButton import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue 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.res.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.cornellappdev.score.model.Sport -import com.cornellappdev.score.theme.GrayStroke +import com.cornellappdev.score.theme.GrayLight +import com.cornellappdev.score.theme.GrayPrimary +import com.cornellappdev.score.theme.Stroke import com.cornellappdev.score.theme.Style.bodyNormal +import com.cornellappdev.score.theme.White import com.cornellappdev.score.util.sportList @Composable -fun HighlightsFilterButton( +private fun HighlightsFilterButton( sport: Sport, - onFilterSelected: (Sport) -> Unit + onFilterSelected: (Sport) -> Unit, + isSelected: Boolean = false, ) { - Row( + OutlinedButton( modifier = Modifier - .height(32.dp) - .border( - width = 1.dp, - color = GrayStroke, - shape = RoundedCornerShape(100) - ) - .background(color = Color.White, shape = RoundedCornerShape(100)) - .padding(horizontal = 12.dp, vertical = 4.dp) - .clip(shape = RoundedCornerShape(100)) - .clickable { onFilterSelected }, - verticalAlignment = Alignment.CenterVertically, + .height(32.dp), + border = BorderStroke(width = 1.dp, color = Stroke), + onClick = { onFilterSelected(sport) }, + shape = RoundedCornerShape(100.dp), + colors = outlinedButtonColors( + containerColor = if (isSelected) GrayLight else White, + contentColor = GrayPrimary + ), + contentPadding = PaddingValues(horizontal = 12.dp, vertical = 4.dp), ) { - Image( + Icon( painter = painterResource(sport.emptyIcon), - contentDescription = "sport Icon" + contentDescription = "sport Icon", + tint = Color.Unspecified ) Spacer(modifier = Modifier.width(4.dp)) Text( @@ -60,30 +67,32 @@ fun HighlightsFilterButton( @Composable fun HighlightsFilterRow( + sportList: List, onFilterSelected: (Sport) -> Unit, ) { LazyRow( modifier = Modifier - .fillMaxWidth() - .padding(start = 24.dp), - horizontalArrangement = Arrangement.SpaceBetween, + .fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(12.dp), verticalAlignment = Alignment.CenterVertically ) { - items(sportList.size) { i -> - HighlightsFilterButton(sportList[i], { onFilterSelected(sportList[i]) }) - Spacer(Modifier.width(12.dp)) + item { Spacer(Modifier.width(12.dp)) } + items(sportList) { item -> + HighlightsFilterButton(item, onFilterSelected) } + item { Spacer(Modifier.width(12.dp)) } } } @Preview @Composable private fun HighlightsFilterButtonPreview() { - HighlightsFilterButton(Sport.BASEBALL, {}) + var isSelected by remember { mutableStateOf(false) } + HighlightsFilterButton(Sport.BASEBALL, { isSelected = !isSelected }, isSelected = isSelected) } @Preview @Composable private fun HighlightsFilterRowPreview() { - HighlightsFilterRow({}) + HighlightsFilterRow(sportList, {}) } From 742065646bb0f6edfba7483f3375fef8e9ec5361 Mon Sep 17 00:00:00 2001 From: amjiao Date: Mon, 3 Nov 2025 11:18:54 -0500 Subject: [PATCH 14/17] Search Bar refactoring --- .../highlights/HighlightsScreenHeader.kt | 52 +++++ .../highlights/HighlightsSearchBar.kt | 91 +++++++++ .../score/screen/HighlightsScreen.kt | 186 ++++-------------- 3 files changed, 185 insertions(+), 144 deletions(-) create mode 100644 app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsScreenHeader.kt create mode 100644 app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsSearchBar.kt diff --git a/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsScreenHeader.kt b/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsScreenHeader.kt new file mode 100644 index 0000000..65b15c6 --- /dev/null +++ b/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsScreenHeader.kt @@ -0,0 +1,52 @@ +package com.cornellappdev.score.components.highlights + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +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 +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.cornellappdev.score.components.ScorePreview +import com.cornellappdev.score.model.Sport +import com.cornellappdev.score.theme.Style.heading1 +import com.cornellappdev.score.util.sportList + +@Composable +fun HighlightsScreenHeader( + sportList: List, +) { + Column(modifier = Modifier.fillMaxWidth()) { + Text( + modifier = Modifier.padding(start = 24.dp), + style = heading1, + text = "Highlights" + ) + Spacer(modifier = Modifier.height(12.dp)) + Row( + modifier = Modifier + .padding(horizontal = 24.dp) + .clip(shape = RoundedCornerShape(100.dp)) + .clickable(onClick = {/*todo clear the highlight rows and show recent searches*/ }) + ) { + HighlightsSearchBar({}) + } + Spacer(modifier = Modifier.height(16.dp)) + HighlightsFilterRow(sportList, {/*todo on filter selected*/ }) + } +} + +@Preview +@Composable +private fun HighlightsScreenHeaderPreview() { + ScorePreview { + HighlightsScreenHeader(sportList) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsSearchBar.kt b/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsSearchBar.kt new file mode 100644 index 0000000..36245fd --- /dev/null +++ b/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsSearchBar.kt @@ -0,0 +1,91 @@ +package com.cornellappdev.score.components.highlights + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.BasicTextField +import androidx.compose.material3.Icon +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +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.res.painterResource +import androidx.compose.ui.text.input.VisualTransformation +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.cornellappdev.score.R +import com.cornellappdev.score.theme.GrayLight +import com.cornellappdev.score.theme.Style.bodyNormal + +@Composable +fun HighlightsSearchBar( + onSearchClick: () -> Unit +) { + val interactionSource = remember { MutableInteractionSource() } + var searchQuery by remember { mutableStateOf("") } + + Box( + modifier = Modifier + .fillMaxWidth() + .background(Color.White, RoundedCornerShape(100.dp)) + .border(1.dp, GrayLight, RoundedCornerShape(100.dp)) + .clip(RoundedCornerShape(100.dp)) + .clickable( + interactionSource = interactionSource, + indication = null + ) { onSearchClick() } + .padding(horizontal = 16.dp, vertical = 8.dp) + ) { + Row(verticalAlignment = Alignment.CenterVertically) { + + Icon( + painter = painterResource(R.drawable.search), + contentDescription = "search icon", + tint = Color.Unspecified + ) + + Spacer(Modifier.width(8.dp)) + + Box(modifier = Modifier.weight(1f)) { + if (searchQuery.isEmpty()) { + Text( + text = "Search keywords", + style = bodyNormal.copy(color = Color.Gray) + ) + } + + BasicTextField( + value = searchQuery, + onValueChange = { searchQuery = it }, + singleLine = true, + textStyle = bodyNormal, + visualTransformation = VisualTransformation.None, + interactionSource = interactionSource, + modifier = Modifier + .fillMaxWidth() + .background(Color.Transparent) + ) + } + } + } +} + +@Preview +@Composable +private fun HighlightsSearchBarPreview() { + HighlightsSearchBar({}) +} \ No newline at end of file diff --git a/app/src/main/java/com/cornellappdev/score/screen/HighlightsScreen.kt b/app/src/main/java/com/cornellappdev/score/screen/HighlightsScreen.kt index f0e035f..1fb9472 100644 --- a/app/src/main/java/com/cornellappdev/score/screen/HighlightsScreen.kt +++ b/app/src/main/java/com/cornellappdev/score/screen/HighlightsScreen.kt @@ -1,147 +1,33 @@ package com.cornellappdev.score.screen -import androidx.compose.foundation.Image import androidx.compose.foundation.background -import androidx.compose.foundation.border -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer 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.lazy.LazyRow -import androidx.compose.foundation.shape.RoundedCornerShape -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.BlendMode import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.ColorFilter -import androidx.compose.ui.res.painterResource 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.R -import com.cornellappdev.score.components.highlights.ArticleHighlightCard import com.cornellappdev.score.components.EmptyStateBox -import com.cornellappdev.score.components.highlights.HighlightsFilterRow -import com.cornellappdev.score.components.highlights.VideoHighlightCard -import com.cornellappdev.score.model.ArticleHighlightData -import com.cornellappdev.score.model.VideoHighlightData -import com.cornellappdev.score.theme.GrayLight -import com.cornellappdev.score.theme.GrayMedium -import com.cornellappdev.score.theme.Style.bodyNormal -import com.cornellappdev.score.theme.Style.heading1 -import com.cornellappdev.score.theme.Style.heading2 +import com.cornellappdev.score.components.ScorePreview +import com.cornellappdev.score.components.highlights.HighlightsCardRow +import com.cornellappdev.score.components.highlights.HighlightsScreenHeader +import com.cornellappdev.score.model.HighlightData +import com.cornellappdev.score.model.Sport import com.cornellappdev.score.util.highlightsList +import com.cornellappdev.score.util.sportList -@Composable -fun HighlightsScreenHeader( - onSearch: () -> Unit -) { - Column(modifier = Modifier.fillMaxWidth()) { - Text( - modifier = Modifier.padding(start = 24.dp), - style = heading1, - text = "Highlights" - ) - Spacer(modifier = Modifier.height(12.dp)) - Row( - modifier = Modifier - .padding(horizontal = 24.dp) - .border(width = 1.dp, color = GrayLight, shape = RoundedCornerShape(100.dp)) - .background(color = Color.White, shape = RoundedCornerShape(100.dp)) - .fillMaxWidth() - .clip(shape = RoundedCornerShape(100.dp)) - .clickable { onSearch }, - verticalAlignment = Alignment.CenterVertically - ) { - Row( - modifier = Modifier.padding(8.dp), - verticalAlignment = Alignment.CenterVertically - ) { - Image( - painter = painterResource(R.drawable.search), - contentDescription = "search icon" - ) - Spacer(modifier = Modifier.width(4.dp)) - Text( - text = "Search keywords", - style = bodyNormal - ) - } - } - Spacer(modifier = Modifier.height(16.dp)) - HighlightsFilterRow({/*todo on filter selected*/}) - } -} - -@Composable -fun HighlightsCardRow( - highlightsList: List -) { - Column( - modifier = Modifier.fillMaxWidth() - ) { - Row( - modifier = Modifier - .padding(horizontal = 24.dp) - .fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically - ) { - Text( - text = "Today", - style = heading2 - ) - Row( - modifier = Modifier.clickable {/*todo navigation to Today screen*/ }, - verticalAlignment = Alignment.CenterVertically - ) { - Text( - text = "${highlightsList.size} Results", - style = bodyNormal - ) - Image( - painter = painterResource(R.drawable.ic_right_chevron), - contentDescription = "right chevron", - colorFilter = ColorFilter.tint(GrayMedium, blendMode = BlendMode.SrcIn) - ) - } - } - Spacer(modifier = Modifier.height(16.dp)) - LazyRow( - modifier = Modifier.padding(start = 24.dp) - ) { - items(highlightsList.size) { i -> - if (highlightsList[i] is VideoHighlightData) { - VideoHighlightCard( - highlightsList[i] as VideoHighlightData, - false - ) - } else if (highlightsList[i] is ArticleHighlightData) { - ArticleHighlightCard( - highlightsList[i] as ArticleHighlightData, - false - ) - } - - Spacer(modifier = Modifier.width(16.dp)) - } - } - Spacer(modifier = Modifier.height(24.dp)) - } -} - +/*todo: needs a UIState */ @Composable fun HighlightsScreen( - todayHighlightsList: List, - pastThreeHighlightsList: List + sportList: List, + todayHighlightsList: List, + pastThreeHighlightsList: List ) { Column( modifier = Modifier @@ -149,19 +35,19 @@ fun HighlightsScreen( .background(color = Color.White) ) { Spacer(modifier = Modifier.height(24.dp)) - HighlightsScreenHeader({}) + HighlightsScreenHeader(sportList) Spacer(modifier = Modifier.height(24.dp)) - if (todayHighlightsList.isEmpty() and pastThreeHighlightsList.isEmpty()) { + if (todayHighlightsList.isEmpty() && pastThreeHighlightsList.isEmpty()) { EmptyStateBox( icon = R.drawable.kid_star, - title = "No results yet." + title = "No results yet.", ) } if (todayHighlightsList.isNotEmpty()) { - HighlightsCardRow(todayHighlightsList) + HighlightsCardRow(todayHighlightsList, "Today") } if (pastThreeHighlightsList.isNotEmpty()) { - HighlightsCardRow(pastThreeHighlightsList) + HighlightsCardRow(pastThreeHighlightsList, "Past 3 days") } } } @@ -169,23 +55,35 @@ fun HighlightsScreen( @Composable @Preview private fun HighlightsScreenHeaderPreview() { - HighlightsScreenHeader({}) + ScorePreview { + HighlightsScreenHeader(sportList) + } } -@Composable -@Preview -private fun HighlightsScreenPreview() { - HighlightsScreen(highlightsList, highlightsList) -} +data class HighlightsScreenPreviewData( + val sportList: List, + val todayHighlightList: List, + val pastHighlightList: List +) -@Composable -@Preview -private fun EmptyHighlightsScreenPreview() { - HighlightsScreen(emptyList(), emptyList()) +class HighlightsScreenPreviewProvider : PreviewParameterProvider { + override val values: Sequence = sequence { + yield(HighlightsScreenPreviewData(sportList, highlightsList, highlightsList)) + yield(HighlightsScreenPreviewData(sportList, emptyList(), emptyList())) + yield(HighlightsScreenPreviewData(sportList, emptyList(), highlightsList)) + } } +@Preview(showBackground = true) @Composable -@Preview -private fun PartialHighlightsScreenPreview() { - HighlightsScreen(emptyList(), highlightsList) +private fun VideoHighlightCardPreview( + @PreviewParameter(HighlightsScreenPreviewProvider::class) previewData: HighlightsScreenPreviewData +) { + ScorePreview { + HighlightsScreen( + sportList = previewData.sportList, + todayHighlightsList = previewData.todayHighlightList, + pastThreeHighlightsList = previewData.pastHighlightList, + ) + } } \ No newline at end of file From cd1b24b65269c099b373f43ce61246de7bfcebef Mon Sep 17 00:00:00 2001 From: amjiao Date: Mon, 3 Nov 2025 11:19:07 -0500 Subject: [PATCH 15/17] Utils --- .../cornellappdev/score/theme/TextStyle.kt | 18 ++++++---- .../score/util/TestingConstants.kt | 35 ++++++++++++------- .../res/drawable/ic_right_chevron_small.xml | 13 +++++++ 3 files changed, 48 insertions(+), 18 deletions(-) create mode 100644 app/src/main/res/drawable/ic_right_chevron_small.xml 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 c2fd46e..c01fafa 100644 --- a/app/src/main/java/com/cornellappdev/score/theme/TextStyle.kt +++ b/app/src/main/java/com/cornellappdev/score/theme/TextStyle.kt @@ -8,7 +8,6 @@ import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp object Style { @@ -25,11 +24,11 @@ object Style { fontWeight = FontWeight(700), fontStyle = FontStyle.Italic, color = Color.White, - shadow = Shadow( - color = Color(0f, 0f, 0f, 0.4f), - offset = Offset(0f, 0f), - blurRadius = 4f - ) + shadow = Shadow( + color = Color(0f, 0f, 0f, 0.4f), + offset = Offset(0f, 0f), + blurRadius = 4f + ) ) val universityText = TextStyle( @@ -154,6 +153,13 @@ object Style { fontWeight = FontWeight(400) ) + val bodyNormalGray = TextStyle( + fontSize = 14.sp, + fontFamily = poppinsFamily, + fontWeight = FontWeight(400), + color = GrayMedium + ) + val spanBodyNormal = SpanStyle( fontSize = 14.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 add8a0c..6d066e4 100644 --- a/app/src/main/java/com/cornellappdev/score/util/TestingConstants.kt +++ b/app/src/main/java/com/cornellappdev/score/util/TestingConstants.kt @@ -6,6 +6,7 @@ import com.cornellappdev.score.model.ArticleHighlightData import com.cornellappdev.score.model.GameCardData import com.cornellappdev.score.model.GameData import com.cornellappdev.score.model.GenderDivision +import com.cornellappdev.score.model.HighlightData import com.cornellappdev.score.model.VideoHighlightData import com.cornellappdev.score.model.ScoreEvent import com.cornellappdev.score.model.Sport @@ -219,44 +220,54 @@ val sportSelectionList = listOf( SportSelection.SportSelect(Sport.BASEBALL), SportSelection.SportSelect(Sport.BASKETBALL), SportSelection.SportSelect(Sport.CROSS_COUNTRY), + SportSelection.SportSelect(Sport.EQUESTRIAN), + SportSelection.SportSelect(Sport.FENCING), + SportSelection.SportSelect(Sport.FIELD_HOCKEY) ) //Mixed type val highlightsList = listOf( - VideoHighlightData( + HighlightData.Video + (VideoHighlightData( "vs Columbia", "maxresdefault.jpg", "https://cornellsun.com/article/london-mcdavid-is-making-a-name-for-herself-at-cornell", "11/09", Sport.BASEBALL, GenderDivision.MALE - ), - ArticleHighlightData( + )), + HighlightData.Article + (ArticleHighlightData( "Late Goal Lifts No. 6 Men’s Hockey Over Brown", "maxresdefault.jpg", "https://cornellsun.com/article/london-mcdavid-is-making-a-name-for-herself-at-cornell", - "11/09" - ), - VideoHighlightData( + "11/09", + Sport.ICE_HOCKEY + )), + HighlightData.Video + (VideoHighlightData( "vs Columbia", "maxresdefault.jpg", "https://cornellsun.com/article/london-mcdavid-is-making-a-name-for-herself-at-cornell", "11/9", Sport.BASEBALL, GenderDivision.MALE - ), - ArticleHighlightData( + )), + HighlightData.Article + (ArticleHighlightData( "Late Goal Lifts No. 6 Men’s Hockey Over Brown", "maxresdefault.jpg", "https://cornellsun.com/article/london-mcdavid-is-making-a-name-for-herself-at-cornell", - "11/09" - ), - VideoHighlightData( + "11/09", + Sport.ICE_HOCKEY + )), + HighlightData.Video + (VideoHighlightData( "vs Columbia", "maxresdefault.jpg", "https://cornellsun.com/article/london-mcdavid-is-making-a-name-for-herself-at-cornell", "11/9", Sport.BASEBALL, GenderDivision.MALE - ) + )) ) \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_right_chevron_small.xml b/app/src/main/res/drawable/ic_right_chevron_small.xml new file mode 100644 index 0000000..e2190fe --- /dev/null +++ b/app/src/main/res/drawable/ic_right_chevron_small.xml @@ -0,0 +1,13 @@ + + + + + + From ec47aa624a34ed43d6b248109ff8f12c46971f1d Mon Sep 17 00:00:00 2001 From: amjiao Date: Mon, 3 Nov 2025 11:27:56 -0500 Subject: [PATCH 16/17] Fix padding to match design --- .../com/cornellappdev/score/components/SportSelectorHeader.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/src/main/java/com/cornellappdev/score/components/SportSelectorHeader.kt b/app/src/main/java/com/cornellappdev/score/components/SportSelectorHeader.kt index 2f4e7d7..fd09f9a 100644 --- a/app/src/main/java/com/cornellappdev/score/components/SportSelectorHeader.kt +++ b/app/src/main/java/com/cornellappdev/score/components/SportSelectorHeader.kt @@ -82,7 +82,6 @@ fun SportSelectorHeader( Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(20.dp) ) { - item { Spacer(Modifier.width(4.dp)) } items(sports) { selection -> when (selection) { SportSelection.All -> { @@ -113,7 +112,6 @@ fun SportSelectorHeader( } } } - item { Spacer(modifier = Modifier.width(4.dp)) } } } } From 707b6b4e7c3271a9a07c67e9532e1a2eb2755e90 Mon Sep 17 00:00:00 2001 From: amjiao Date: Wed, 12 Nov 2025 12:46:52 -0500 Subject: [PATCH 17/17] Address PR comments --- .../score/components/EmptyState.kt | 7 ++- .../highlights/ArticleHighlightsCard.kt | 40 +++++--------- .../components/highlights/ExternalLink.kt | 55 +++++++++++++++++++ .../highlights/HighlightsCardRow.kt | 4 +- .../highlights/HighlightsSearchBar.kt | 54 +++++++++--------- .../highlights/VideoHighlightsCard.kt | 52 +++++------------- ...ow_outward_white.xml => arrow_outward.xml} | 0 .../main/res/drawable/arrow_outward_red.xml | 13 ----- 8 files changed, 115 insertions(+), 110 deletions(-) create mode 100644 app/src/main/java/com/cornellappdev/score/components/highlights/ExternalLink.kt rename app/src/main/res/drawable/{arrow_outward_white.xml => arrow_outward.xml} (100%) delete mode 100644 app/src/main/res/drawable/arrow_outward_red.xml diff --git a/app/src/main/java/com/cornellappdev/score/components/EmptyState.kt b/app/src/main/java/com/cornellappdev/score/components/EmptyState.kt index 837473d..3b5843f 100644 --- a/app/src/main/java/com/cornellappdev/score/components/EmptyState.kt +++ b/app/src/main/java/com/cornellappdev/score/components/EmptyState.kt @@ -8,10 +8,12 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height +import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Dp @@ -40,9 +42,10 @@ fun EmptyStateBox( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center ) { - Image( + Icon( painter = painterResource(icon), - contentDescription = "empty state icon" + contentDescription = "empty state icon", + tint = Color.Unspecified ) Spacer(modifier = Modifier.height(16.dp)) Text( 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 352fa0c..bc34227 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 @@ -42,11 +42,11 @@ import com.cornellappdev.score.theme.White @Composable fun ArticleHighlightCard( articleHighlight: ArticleHighlightData, - modifier: Modifier = Modifier //for wide cards, specify Modifier.fillMaxWidth() + isWideFormat: Boolean ) { Box( - modifier = modifier - .width(241.dp) + modifier = Modifier + .then(if (isWideFormat) Modifier.fillMaxWidth() else Modifier.width(241.dp)) .height(192.dp) .clip(shape = RoundedCornerShape(12.dp)) ) { @@ -83,28 +83,13 @@ fun ArticleHighlightCard( Row( verticalAlignment = Alignment.CenterVertically ) { - BasicText( - style = bodySemibold, - text = buildAnnotatedString { - withLink( - LinkAnnotation.Url( - articleHighlight.articleUrl, - TextLinkStyles( - style = SpanStyle( - textDecoration = TextDecoration.Underline, - color = White - ) - ), - ) - ) { - append("Cornell Daily Sun") - } - } - ) - Icon( - painter = painterResource(R.drawable.arrow_outward_white), - contentDescription = "external link arrow", - tint = Color.Unspecified + if (isWideFormat) { + Text("Read at ", color = White) + } + ExternalLink( + articleHighlight.articleUrl, + urlLabel = "Cornell Daily Sun", + linkColor = White ) } Text( @@ -127,7 +112,8 @@ private fun ArticleHighlightCardPreview() { "https://cornellsun.com/article/london-mcdavid-is-making-a-name-for-herself-at-cornell", "11/9", Sport.ICE_HOCKEY - ) + ), + false ) } @@ -142,6 +128,6 @@ private fun WideArticleHighlightCardPreview() { "11/9", Sport.ICE_HOCKEY ), - Modifier.fillMaxWidth() + true ) } \ No newline at end of file diff --git a/app/src/main/java/com/cornellappdev/score/components/highlights/ExternalLink.kt b/app/src/main/java/com/cornellappdev/score/components/highlights/ExternalLink.kt new file mode 100644 index 0000000..957400f --- /dev/null +++ b/app/src/main/java/com/cornellappdev/score/components/highlights/ExternalLink.kt @@ -0,0 +1,55 @@ +package com.cornellappdev.score.components.highlights + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.text.BasicText +import androidx.compose.material3.Icon +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +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.font.FontWeight +import androidx.compose.ui.text.style.TextDecoration +import androidx.compose.ui.text.withLink +import com.cornellappdev.score.R + +@Composable +fun ExternalLink( + url: String, + urlLabel: String, + linkColor: Color, +) { + Row( + verticalAlignment = Alignment.CenterVertically + ) { + BasicText( + text = buildAnnotatedString { + withLink( + LinkAnnotation.Url( + url, + TextLinkStyles( + style = SpanStyle( + textDecoration = TextDecoration.Underline, + color = linkColor, + fontWeight = FontWeight.Bold + ) + ), + ) + ) { + append(urlLabel) + } + } + ) + Icon( + painter = painterResource(R.drawable.arrow_outward), + contentDescription = "external link arrow", + tint = linkColor + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsCardRow.kt b/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsCardRow.kt index 107906e..57755f6 100644 --- a/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsCardRow.kt +++ b/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsCardRow.kt @@ -68,8 +68,8 @@ fun HighlightsCardRow( item { Spacer(Modifier.width(8.dp)) } items(highlightsList) { item -> when (item) { - is HighlightData.Video -> VideoHighlightCard(item.data) - is HighlightData.Article -> ArticleHighlightCard(item.data) + is HighlightData.Video -> VideoHighlightCard(item.data, false) + is HighlightData.Article -> ArticleHighlightCard(item.data, false) } } item { Spacer(Modifier.width(8.dp)) } diff --git a/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsSearchBar.kt b/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsSearchBar.kt index 36245fd..892daa2 100644 --- a/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsSearchBar.kt +++ b/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsSearchBar.kt @@ -38,7 +38,7 @@ fun HighlightsSearchBar( val interactionSource = remember { MutableInteractionSource() } var searchQuery by remember { mutableStateOf("") } - Box( + Row( modifier = Modifier .fillMaxWidth() .background(Color.White, RoundedCornerShape(100.dp)) @@ -48,38 +48,36 @@ fun HighlightsSearchBar( interactionSource = interactionSource, indication = null ) { onSearchClick() } - .padding(horizontal = 16.dp, vertical = 8.dp) - ) { - Row(verticalAlignment = Alignment.CenterVertically) { + .padding(horizontal = 16.dp, vertical = 8.dp), + verticalAlignment = Alignment.CenterVertically) { - Icon( - painter = painterResource(R.drawable.search), - contentDescription = "search icon", - tint = Color.Unspecified - ) - - Spacer(Modifier.width(8.dp)) + Icon( + painter = painterResource(R.drawable.search), + contentDescription = "search icon", + tint = Color.Unspecified + ) - Box(modifier = Modifier.weight(1f)) { - if (searchQuery.isEmpty()) { - Text( - text = "Search keywords", - style = bodyNormal.copy(color = Color.Gray) - ) - } + Spacer(Modifier.width(8.dp)) - BasicTextField( - value = searchQuery, - onValueChange = { searchQuery = it }, - singleLine = true, - textStyle = bodyNormal, - visualTransformation = VisualTransformation.None, - interactionSource = interactionSource, - modifier = Modifier - .fillMaxWidth() - .background(Color.Transparent) + Box(modifier = Modifier.weight(1f)) { + if (searchQuery.isEmpty()) { + Text( + text = "Search keywords", + style = bodyNormal.copy(color = Color.Gray) ) } + + BasicTextField( + value = searchQuery, + onValueChange = { searchQuery = it }, + singleLine = true, + textStyle = bodyNormal, + visualTransformation = VisualTransformation.None, + interactionSource = interactionSource, + modifier = Modifier + .fillMaxWidth() + .background(Color.Transparent) + ) } } } diff --git a/app/src/main/java/com/cornellappdev/score/components/highlights/VideoHighlightsCard.kt b/app/src/main/java/com/cornellappdev/score/components/highlights/VideoHighlightsCard.kt index e7921b1..44c4efb 100644 --- a/app/src/main/java/com/cornellappdev/score/components/highlights/VideoHighlightsCard.kt +++ b/app/src/main/java/com/cornellappdev/score/components/highlights/VideoHighlightsCard.kt @@ -14,7 +14,6 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size 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 @@ -24,13 +23,7 @@ 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.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameterProvider @@ -71,7 +64,8 @@ private fun VideoHighlightCardHeader( @Composable fun VideoHighlightCardBody( - videoHighlight: VideoHighlightData + videoHighlight: VideoHighlightData, + isWideFormat: Boolean ) { Column( modifier = Modifier @@ -122,28 +116,10 @@ fun VideoHighlightCardBody( Row( verticalAlignment = Alignment.CenterVertically ) { - BasicText( - text = buildAnnotatedString { - withLink( - LinkAnnotation.Url( - videoHighlight.videoUrl, - TextLinkStyles( - style = SpanStyle( - textDecoration = TextDecoration.Underline, - color = CrimsonPrimary - ) - ), - ) - ) { - append("YouTube") - } - } - ) - Icon( - painter = painterResource(R.drawable.arrow_outward_red), - contentDescription = "external link arrow", - tint = Color.Unspecified - ) + if (isWideFormat) { + Text("Watch on ") + } + ExternalLink(videoHighlight.videoUrl, "Youtube", CrimsonPrimary) } Text( style = labelsNormal, @@ -156,22 +132,22 @@ fun VideoHighlightCardBody( @Composable fun VideoHighlightCard( videoHighlight: VideoHighlightData, - modifier: Modifier = Modifier //for wide cards, specify Modifier.fillMaxWidth() + isWideFormat: Boolean, + modifier: Modifier = Modifier ) { Column( modifier = modifier - .width(241.dp) + .then(if (isWideFormat) Modifier.fillMaxWidth() else Modifier.width(241.dp)) .clip(RoundedCornerShape(12.dp)) ) { VideoHighlightCardHeader(videoHighlight.thumbnailImageUrl) - - VideoHighlightCardBody(videoHighlight) + VideoHighlightCardBody(videoHighlight, isWideFormat) } } data class VideoHighlightPreviewData( val videoHighlight: VideoHighlightData, - val modifier: Modifier + val isWideFormat: Boolean ) class VideoHighlightsPreviewProvider : PreviewParameterProvider { @@ -195,8 +171,8 @@ class VideoHighlightsPreviewProvider : PreviewParameterProvider - - - - -