From 2ad7bc413befb1e2424af50aeaedb43139905c26 Mon Sep 17 00:00:00 2001 From: amjiao Date: Sat, 28 Feb 2026 17:30:20 -0500 Subject: [PATCH 1/6] Set up navigation between highlights screens --- .../highlights/HighlightsCardRow.kt | 8 +- .../HighlightsScreenSearchFilterBar.kt | 12 +- .../cornellappdev/score/nav/ScoreNavHost.kt | 51 +++++-- .../score/nav/root/RootNavigation.kt | 11 +- .../score/screen/HighlightsScreen.kt | 24 +++- .../score/screen/HighlightsSearchScreen.kt | 56 ++++++-- .../score/screen/HighlightsSubScreen.kt | 132 ++++++++++++++---- 7 files changed, 224 insertions(+), 70 deletions(-) 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 57755f6..72c3d17 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 @@ -23,6 +23,7 @@ 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.screen.HighlightsSubScreenType import com.cornellappdev.score.theme.Style.bodyNormal import com.cornellappdev.score.theme.Style.heading2 import com.cornellappdev.score.util.highlightsList @@ -30,7 +31,8 @@ import com.cornellappdev.score.util.highlightsList @Composable fun HighlightsCardRow( highlightsList: List, - rowHeader: String + rowHeader: String, + toSubScreen: (HighlightsSubScreenType) -> Unit ) { Column( modifier = Modifier.fillMaxWidth() @@ -47,7 +49,7 @@ fun HighlightsCardRow( style = heading2 ) Row( - modifier = Modifier.clickable {/*todo navigation to Today screen*/ }, + modifier = Modifier.clickable { toSubScreen(if (rowHeader == "Today") HighlightsSubScreenType.TODAY else HighlightsSubScreenType.PAST3DAYS) }, verticalAlignment = Alignment.CenterVertically ) { Text( @@ -82,6 +84,6 @@ fun HighlightsCardRow( @Composable private fun HighlightsCardRowPreview() { ScorePreview { - HighlightsCardRow(highlightsList, "Today") + HighlightsCardRow(highlightsList, "Today", {}) } } diff --git a/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsScreenSearchFilterBar.kt b/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsScreenSearchFilterBar.kt index d97ed85..25dddc4 100644 --- a/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsScreenSearchFilterBar.kt +++ b/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsScreenSearchFilterBar.kt @@ -10,19 +10,19 @@ import androidx.compose.ui.Modifier 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.model.SportSelection -import com.cornellappdev.score.util.sportList import com.cornellappdev.score.util.sportSelectionList @Composable fun HighlightsScreenSearchFilterBar( - sportList: List + sportList: List, + onFilterSelected: (SportSelection) -> Unit, + navigateBack: () -> Unit ) { Column(modifier = Modifier.fillMaxWidth()) { - HighlightsSearchBar(modifier = Modifier.padding(horizontal = 24.dp)) + HighlightsSearchBar(modifier = Modifier.padding(horizontal = 24.dp), navigateBack) Spacer(modifier = Modifier.height(16.dp)) - HighlightsFilterRow(sportList, {/*todo on filter selected*/ }) + HighlightsFilterRow(sportList, onFilterSelected) } } @@ -30,6 +30,6 @@ fun HighlightsScreenSearchFilterBar( @Composable private fun HighlightsScreenSearchFilterBarPreview() { ScorePreview { - HighlightsScreenSearchFilterBar(sportSelectionList) + HighlightsScreenSearchFilterBar(sportSelectionList, {}, navigateBack = {}) } } \ No newline at end of file diff --git a/app/src/main/java/com/cornellappdev/score/nav/ScoreNavHost.kt b/app/src/main/java/com/cornellappdev/score/nav/ScoreNavHost.kt index b0e916b..0481a2e 100644 --- a/app/src/main/java/com/cornellappdev/score/nav/ScoreNavHost.kt +++ b/app/src/main/java/com/cornellappdev/score/nav/ScoreNavHost.kt @@ -14,12 +14,10 @@ import com.cornellappdev.score.nav.root.ScoreScreens.Home import com.cornellappdev.score.screen.GameDetailsScreen import com.cornellappdev.score.screen.HighlightsScreen import com.cornellappdev.score.screen.HighlightsSearchScreen +import com.cornellappdev.score.screen.HighlightsSubScreen +import com.cornellappdev.score.screen.HighlightsSubScreenType import com.cornellappdev.score.screen.HomeScreen import com.cornellappdev.score.screen.PastGamesScreen -import com.cornellappdev.score.util.highlightsList -import com.cornellappdev.score.util.recentSearchList -import com.cornellappdev.score.util.sportList -import com.cornellappdev.score.util.sportSelectionList import kotlinx.serialization.builtins.ListSerializer import kotlinx.serialization.json.Json @@ -69,23 +67,48 @@ fun ScoreNavHost(navController: NavHostController) { }) } - composable { backStackEntry -> + composable { CompositionLocalProvider(LocalViewModelStoreOwner provides mainScreenViewModelStoreOwner) { - HighlightsScreen(toSearchScreen = { navController.navigate(ScoreScreens.HighlightsSearchScreen) }) + HighlightsScreen( + toSearchScreen = { + navController.navigate( + ScoreScreens.HighlightsSearchScreen( + HighlightsSubScreenType.ALL + ) + ) + }, + toSubScreen = { subScreenType -> + navController.navigate(ScoreScreens.HighlightsSubScreen(subScreenType)) + }) } } + composable { backStackEntry -> + val route = backStackEntry.toRoute() + val subScreenType = route.subScreenType + + HighlightsSubScreen( + toSearchScreen = { + navController.navigate( + ScoreScreens.HighlightsSearchScreen(subScreenType) + ) + }, + navigateBack = { navController.popBackStack() }, + subScreenType = subScreenType + ) + } + composable { backStackEntry -> CompositionLocalProvider(LocalViewModelStoreOwner provides mainScreenViewModelStoreOwner) { + + val route = + backStackEntry.toRoute() + + val searchScreenType = route.subScreenType + HighlightsSearchScreen( - //todo - will un-hardcode this when i do the networking - sportList = sportSelectionList, - recentSearchList = recentSearchList, - highlightsList = highlightsList, - query = "", - header = "Search all highlights", - {}, - {} + searchScreenType = searchScreenType, + navigateBack = { navController.popBackStack() } ) } } diff --git a/app/src/main/java/com/cornellappdev/score/nav/root/RootNavigation.kt b/app/src/main/java/com/cornellappdev/score/nav/root/RootNavigation.kt index a837957..c727d18 100644 --- a/app/src/main/java/com/cornellappdev/score/nav/root/RootNavigation.kt +++ b/app/src/main/java/com/cornellappdev/score/nav/root/RootNavigation.kt @@ -28,6 +28,7 @@ import androidx.navigation.toRoute import com.cornellappdev.score.R import com.cornellappdev.score.nav.ScoreNavHost import com.cornellappdev.score.nav.ScoreNavigationBar +import com.cornellappdev.score.screen.HighlightsSubScreenType import com.cornellappdev.score.theme.LocalInfiniteLoading import com.cornellappdev.score.theme.White import kotlinx.serialization.Serializable @@ -114,7 +115,14 @@ sealed class ScoreScreens { data object HighlightsScreen : ScoreScreens() @Serializable - data object HighlightsSearchScreen : ScoreScreens() + data class HighlightsSubScreen( + val subScreenType: HighlightsSubScreenType + ) : ScoreScreens() + + @Serializable + data class HighlightsSearchScreen( + val subScreenType: HighlightsSubScreenType + ) : ScoreScreens() } fun NavBackStackEntry.toScreen(): ScoreScreens? = @@ -125,6 +133,7 @@ fun NavBackStackEntry.toScreen(): ScoreScreens? = "GameScoreSummaryPage" -> toRoute() "HighlightsScreen" -> toRoute() "HighlightsSearchScreen" -> toRoute() + "HighlightsSubScreen" -> toRoute() else -> throw IllegalArgumentException("Invalid screen") } 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 8d52592..4154e77 100644 --- a/app/src/main/java/com/cornellappdev/score/screen/HighlightsScreen.kt +++ b/app/src/main/java/com/cornellappdev/score/screen/HighlightsScreen.kt @@ -31,11 +31,13 @@ import com.cornellappdev.score.theme.Style.heading1 import com.cornellappdev.score.util.highlightsList import com.cornellappdev.score.util.sportSelectionList import com.cornellappdev.score.viewmodel.HighlightsViewModel +import kotlinx.serialization.Serializable @Composable fun HighlightsScreen( highlightsViewModel: HighlightsViewModel = hiltViewModel(), - toSearchScreen: () -> Unit + toSearchScreen: () -> Unit, + toSubScreen: (HighlightsSubScreenType) -> Unit ) { val uiState = highlightsViewModel.collectUiStateValue() @@ -65,7 +67,8 @@ fun HighlightsScreen( onSportSelected = { highlightsViewModel.onSportSelected(it) }, todayHighlightsList = uiState.todayHighlights, pastThreeHighlightsList = uiState.pastThreeDaysHighlights, - toSearchScreen = toSearchScreen + toSearchScreen = toSearchScreen, + toSubScreen = toSubScreen ) } } @@ -73,13 +76,19 @@ fun HighlightsScreen( } } +@Serializable +enum class HighlightsSubScreenType{ + TODAY, PAST3DAYS, ALL +} + @Composable private fun HighlightsScreenContent( - sportList: List = emptyList(), onSportSelected: (SportSelection) -> Unit, + sportList: List = emptyList(), todayHighlightsList: List = emptyList(), pastThreeHighlightsList: List = emptyList(), - toSearchScreen: () -> Unit + toSearchScreen: () -> Unit, + toSubScreen: (HighlightsSubScreenType) -> Unit ) { Column( modifier = Modifier.fillMaxSize() @@ -101,10 +110,10 @@ private fun HighlightsScreenContent( ) } if (todayHighlightsList.isNotEmpty()) { - HighlightsCardRow(todayHighlightsList, "Today") + HighlightsCardRow(todayHighlightsList, "Today", toSubScreen ) } if (pastThreeHighlightsList.isNotEmpty()) { - HighlightsCardRow(pastThreeHighlightsList, "Past 3 days") + HighlightsCardRow(pastThreeHighlightsList, "Past 3 days", toSubScreen) } } } @@ -135,7 +144,8 @@ private fun HighlightScreenPreview( todayHighlightsList = previewData.todayHighlightList, pastThreeHighlightsList = previewData.pastHighlightList, toSearchScreen = {}, - onSportSelected = {} + onSportSelected = {}, + toSubScreen = {} ) } } \ No newline at end of file diff --git a/app/src/main/java/com/cornellappdev/score/screen/HighlightsSearchScreen.kt b/app/src/main/java/com/cornellappdev/score/screen/HighlightsSearchScreen.kt index d4bec11..58fb227 100644 --- a/app/src/main/java/com/cornellappdev/score/screen/HighlightsSearchScreen.kt +++ b/app/src/main/java/com/cornellappdev/score/screen/HighlightsSearchScreen.kt @@ -8,39 +8,71 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding 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.Modifier import androidx.compose.ui.graphics.Color 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 androidx.hilt.navigation.compose.hiltViewModel import com.cornellappdev.score.components.ScorePreview import com.cornellappdev.score.components.highlights.HighlightsCardLazyColumn import com.cornellappdev.score.components.highlights.HighlightsCardLazyColumnResultsHeader import com.cornellappdev.score.components.highlights.HighlightsScreenSearchFilterBar import com.cornellappdev.score.model.HighlightData -import com.cornellappdev.score.model.Sport import com.cornellappdev.score.model.SportSelection import com.cornellappdev.score.theme.Style.heading2 import com.cornellappdev.score.util.highlightsList import com.cornellappdev.score.util.recentSearchList -import com.cornellappdev.score.util.sportList import com.cornellappdev.score.util.sportSelectionList +import com.cornellappdev.score.viewmodel.HighlightsViewModel + @Composable fun HighlightsSearchScreen( + highlightsViewModel: HighlightsViewModel = hiltViewModel(), + navigateBack: () -> Unit, + searchScreenType: HighlightsSubScreenType +) { + val uiState = highlightsViewModel.collectUiStateValue() + + val (highlightsList, header) = when (searchScreenType) { + HighlightsSubScreenType.TODAY -> + uiState.todayHighlights to "Search today" + + HighlightsSubScreenType.PAST3DAYS -> + uiState.pastThreeDaysHighlights to "Search past 3 days" + + HighlightsSubScreenType.ALL -> + uiState.filteredHighlights to "Search all highlights" + } + + HighlightsSearchScreenContent( + sportList = uiState.sportSelectionList, + onFilterSelected = { highlightsViewModel.onSportSelected(it) }, + recentSearchList = emptyList(), /*todo implement in VM*/ + highlightsList = highlightsList, + query = "", + header = header, + onItemClick = {}, + onCloseClick = {}, + navigateBack = navigateBack + ) +} + +@Composable +fun HighlightsSearchScreenContent( sportList: List, + onFilterSelected: (SportSelection) -> Unit, recentSearchList: List, highlightsList: List, query: String, header: String, onItemClick: () -> Unit, - onCloseClick: () -> Unit + onCloseClick: () -> Unit, + navigateBack: () -> Unit ) { + Column( modifier = Modifier .fillMaxSize() @@ -51,7 +83,9 @@ fun HighlightsSearchScreen( Spacer(modifier = Modifier.height(16.dp)) HighlightsScreenSearchFilterBar( - sportList + sportList, + onFilterSelected, + navigateBack ) Spacer(modifier = Modifier.height(24.dp)) HighlightsCardLazyColumn( @@ -83,14 +117,16 @@ private fun HighlightScreenPreview( @PreviewParameter(HighlightsSearchScreenPreviewProvider::class) previewData: HighlightsSearchScreenPreviewData ) { ScorePreview { - HighlightsSearchScreen( + HighlightsSearchScreenContent( sportList = previewData.sportList, + onFilterSelected = {}, recentSearchList = previewData.recentSearchList, highlightsList = highlightsList, query = previewData.query, header = "Search All Highlights", onItemClick = {}, - onCloseClick = {} + onCloseClick = {}, + navigateBack = {} ) } } \ No newline at end of file diff --git a/app/src/main/java/com/cornellappdev/score/screen/HighlightsSubScreen.kt b/app/src/main/java/com/cornellappdev/score/screen/HighlightsSubScreen.kt index d7c66c6..59bcbf3 100644 --- a/app/src/main/java/com/cornellappdev/score/screen/HighlightsSubScreen.kt +++ b/app/src/main/java/com/cornellappdev/score/screen/HighlightsSubScreen.kt @@ -3,18 +3,21 @@ package com.cornellappdev.score.screen import androidx.compose.foundation.background import androidx.compose.foundation.clickable 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.wrapContentSize +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items import androidx.compose.material3.Icon import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.dropShadow import androidx.compose.ui.graphics.Color @@ -24,19 +27,24 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.DpOffset import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel import com.cornellappdev.score.R +import com.cornellappdev.score.components.ErrorState +import com.cornellappdev.score.components.LoadingScreen import com.cornellappdev.score.components.ScorePreview -import com.cornellappdev.score.components.highlights.HighlightsCardLazyColumn -import com.cornellappdev.score.components.highlights.HighlightsScreenSearchFilterBar +import com.cornellappdev.score.components.ScorePullToRefreshBox +import com.cornellappdev.score.components.highlights.ArticleHighlightCard +import com.cornellappdev.score.components.highlights.HighlightsFilterRow +import com.cornellappdev.score.components.highlights.HighlightsSearchEntryPointRow +import com.cornellappdev.score.components.highlights.VideoHighlightCard +import com.cornellappdev.score.model.ApiResponse import com.cornellappdev.score.model.HighlightData -import com.cornellappdev.score.model.Sport import com.cornellappdev.score.model.SportSelection import com.cornellappdev.score.theme.Style.heading2 import com.cornellappdev.score.theme.White import com.cornellappdev.score.util.highlightsList -import com.cornellappdev.score.util.recentSearchList -import com.cornellappdev.score.util.sportList import com.cornellappdev.score.util.sportSelectionList +import com.cornellappdev.score.viewmodel.HighlightsViewModel @Composable private fun HighlightsSubScreenHeader( @@ -56,18 +64,19 @@ private fun HighlightsSubScreenHeader( ), color = White ) { - Row( + Box( modifier = Modifier .padding(horizontal = 24.dp, vertical = 12.dp) - .fillMaxWidth(), - horizontalArrangement = Arrangement.spacedBy(96.dp) + .fillMaxWidth() ) { Icon( painter = painterResource(R.drawable.ic_left_arrowhead), contentDescription = "back arrow", - modifier = Modifier.clickable(onClick = { navigateBack() }) + modifier = Modifier + .clickable(onClick = { navigateBack() }) + .align(Alignment.CenterStart) ) - Text(header, style = heading2) + Text(header, style = heading2, modifier = Modifier.align(Alignment.Center)) } } } @@ -82,13 +91,66 @@ private fun HighlightsSubScreenHeaderPreview() { @Composable fun HighlightsSubScreen( + highlightsViewModel: HighlightsViewModel = hiltViewModel(), + navigateBack: () -> Unit, + toSearchScreen: () -> Unit, + subScreenType: HighlightsSubScreenType +) { + val uiState = highlightsViewModel.collectUiStateValue() + + Column( + modifier = Modifier + .fillMaxSize() + .background(color = Color.White) + ) { + when (uiState.loadedState) { + is ApiResponse.Loading -> { + //todo make highlights loading screen, this one's for the home page + LoadingScreen("Loading Highlights...", "Loading Schedules...") + } + + is ApiResponse.Error -> { + ErrorState({ highlightsViewModel.onRefresh() }, "Oops! Highlights failed to load.") + } + + is ApiResponse.Success -> { + ScorePullToRefreshBox( + isRefreshing = uiState.loadedState == ApiResponse.Loading, + { highlightsViewModel.onRefresh() } + ) { + val (highlightsList, header) = when (subScreenType) { + HighlightsSubScreenType.TODAY -> + uiState.todayHighlights to "Today" + + HighlightsSubScreenType.PAST3DAYS -> + uiState.pastThreeDaysHighlights to "Past 3 Days" + + HighlightsSubScreenType.ALL -> + uiState.filteredHighlights to "All highlights" + } + + HighlightsSubScreenContent( + sportList = uiState.sportSelectionList, + onFilterSelected = { highlightsViewModel.onSportSelected(it) }, + highlightsList = highlightsList, + header = header, + navigateBack = navigateBack, + toSearchScreen = toSearchScreen + ) + } + } + } + } +} + +@Composable +fun HighlightsSubScreenContent( sportList: List, - recentSearchList: List, + onFilterSelected: (SportSelection) -> Unit, highlightsList: List, - query: String, header: String, - onItemClick: () -> Unit, - onCloseClick: () -> Unit + navigateBack: () -> Unit, + toSearchScreen: () -> Unit, ) { Column( modifier = Modifier @@ -96,30 +158,42 @@ fun HighlightsSubScreen( .background(color = Color.White) .padding(top = 24.dp) ) { - HighlightsSubScreenHeader(header, {}) + HighlightsSubScreenHeader(header, navigateBack) + Spacer(modifier = Modifier.height(24.dp)) + Column( + modifier = Modifier.padding(horizontal = 24.dp) + ) { + HighlightsSearchEntryPointRow({ toSearchScreen() }) + } Spacer(modifier = Modifier.height(16.dp)) - HighlightsScreenSearchFilterBar( - sportList - ) + HighlightsFilterRow(sportList, onFilterSelected = onFilterSelected) + + Spacer(modifier = Modifier.height(24.dp)) - HighlightsCardLazyColumn( - recentSearchList, - query, - highlightsList, - onItemClick, - onCloseClick - ) + LazyColumn( + Modifier.padding(horizontal = 24.dp), + verticalArrangement = Arrangement.spacedBy(16.dp) + ) { + items(highlightsList) { item -> + when (item) { + is HighlightData.Video -> + VideoHighlightCard(item.data, true) + + is HighlightData.Article -> + ArticleHighlightCard(item.data, true) + } + } + } } } @Preview @Composable private fun HighlightsSubScreenPreview() { - HighlightsSubScreen( + HighlightsSubScreenContent( sportList = sportSelectionList, - recentSearchList = recentSearchList, + onFilterSelected = {}, highlightsList = highlightsList, - query = "s", header = "Past 3 Days", {}, {} ) From 5bb651bca8c12fcd88643ed7017d2c4171823eea Mon Sep 17 00:00:00 2001 From: amjiao Date: Sat, 28 Feb 2026 17:30:42 -0500 Subject: [PATCH 2/6] Small style/user flow fixes --- .../components/highlights/HighlightsFilter.kt | 3 +-- .../highlights/HighlightsSearchBar.kt | 24 +++++++++++-------- 2 files changed, 15 insertions(+), 12 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 69172aa..0d97df6 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 @@ -33,7 +33,6 @@ 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 import com.cornellappdev.score.util.sportSelectionList @Composable @@ -95,7 +94,7 @@ fun HighlightsFilterRow( @Composable private fun HighlightsFilterButtonPreview() { var isSelected by remember { mutableStateOf(false) } - HighlightsFilterButton(Sport.BASEBALL, { isSelected = !isSelected }, isSelected = isSelected) + HighlightsFilterButton(Sport.BASEBALL, { !isSelected }, isSelected = isSelected) } @Preview 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 6d6cae7..fd546aa 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 @@ -12,10 +12,8 @@ import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Arrangement 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 @@ -53,6 +51,7 @@ private fun Modifier.highlightsSearchRowModifier(): Modifier = this @Composable fun HighlightsSearchBar( modifier: Modifier = Modifier, + navigateBack: () -> Unit ) { val interactionSource = remember { MutableInteractionSource() } var searchQuery by remember { mutableStateOf("") } //todo: to be handled by viewmodel @@ -83,7 +82,8 @@ fun HighlightsSearchBar( .weight(1f) .background(Color.Transparent) .onFocusChanged { focusState -> - isFocused = focusState.isFocused /* todo - consider making this an onFocus function in VM */ + isFocused = + focusState.isFocused /* todo - consider making this an onFocus function in VM */ }, decorationBox = { innerTextField -> Row( @@ -136,12 +136,14 @@ fun HighlightsSearchBar( Text( "Cancel", style = bodyMedium, - modifier = Modifier.clickable { - isFocused = false; - focusManager.clearFocus(force = true); - searchQuery = "" - /*todo: clear the text in the search bar*/ - } + modifier = Modifier.clickable( + onClick = { + isFocused = false + focusManager.clearFocus(force = true) + searchQuery = "" + navigateBack() + } + ) ) } } @@ -184,5 +186,7 @@ private fun HighlightsSearchEntryPointRowPreview() { @Preview @Composable private fun HighlightsSearchBarPreview() { - HighlightsSearchBar() + HighlightsSearchBar( + navigateBack = {} + ) } \ No newline at end of file From c3c1cc3d5764e77a8450f32b96f5aa7fff3853ca Mon Sep 17 00:00:00 2001 From: amjiao Date: Fri, 13 Mar 2026 12:31:14 -0400 Subject: [PATCH 3/6] refactor query and filtering functionality to VM --- .../components/highlights/HighlightsFilter.kt | 13 ++- .../HighlightsScreenSearchFilterBar.kt | 14 ++- .../highlights/HighlightsSearchBar.kt | 20 ++-- .../score/screen/HighlightsScreen.kt | 6 +- .../score/screen/HighlightsSearchScreen.kt | 13 ++- .../score/screen/HighlightsSubScreen.kt | 10 +- .../score/viewmodel/HighlightsViewModel.kt | 99 ++++++++++++------- 7 files changed, 119 insertions(+), 56 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 0d97df6..2c92cca 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 @@ -49,7 +49,8 @@ private fun HighlightsFilterButton( shape = RoundedCornerShape(100.dp), colors = outlinedButtonColors( containerColor = if (isSelected) GrayLight else White, - contentColor = GrayPrimary + contentColor = GrayPrimary, + disabledContainerColor = GrayLight ), contentPadding = PaddingValues(horizontal = 12.dp, vertical = 4.dp), ) { @@ -69,6 +70,7 @@ private fun HighlightsFilterButton( @Composable fun HighlightsFilterRow( sportList: List, + selectedSport: SportSelection, onFilterSelected: (SportSelection) -> Unit, ) { LazyRow( @@ -81,13 +83,16 @@ fun HighlightsFilterRow( items = sportList.filterIsInstance(), key = { it.sport } ) { selection -> + + val isSelected = selectedSport == selection + HighlightsFilterButton( sport = selection.sport, - onFilterSelected = onFilterSelected + onFilterSelected = onFilterSelected, + isSelected = isSelected ) } } - } @Preview @@ -100,5 +105,5 @@ private fun HighlightsFilterButtonPreview() { @Preview @Composable private fun HighlightsFilterRowPreview() { - HighlightsFilterRow(sportSelectionList, {}) + HighlightsFilterRow(sportSelectionList, SportSelection.All, {}) } diff --git a/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsScreenSearchFilterBar.kt b/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsScreenSearchFilterBar.kt index 25dddc4..5600e11 100644 --- a/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsScreenSearchFilterBar.kt +++ b/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsScreenSearchFilterBar.kt @@ -16,13 +16,21 @@ import com.cornellappdev.score.util.sportSelectionList @Composable fun HighlightsScreenSearchFilterBar( sportList: List, + query: String, + selectedSport: SportSelection, + onQueryChange: (String) -> Unit, onFilterSelected: (SportSelection) -> Unit, navigateBack: () -> Unit ) { Column(modifier = Modifier.fillMaxWidth()) { - HighlightsSearchBar(modifier = Modifier.padding(horizontal = 24.dp), navigateBack) + HighlightsSearchBar( + modifier = Modifier.padding(horizontal = 24.dp), + query = query, + onQueryChange = onQueryChange, + navigateBack + ) Spacer(modifier = Modifier.height(16.dp)) - HighlightsFilterRow(sportList, onFilterSelected) + HighlightsFilterRow(sportList, selectedSport, onFilterSelected) } } @@ -30,6 +38,6 @@ fun HighlightsScreenSearchFilterBar( @Composable private fun HighlightsScreenSearchFilterBarPreview() { ScorePreview { - HighlightsScreenSearchFilterBar(sportSelectionList, {}, navigateBack = {}) + HighlightsScreenSearchFilterBar(sportSelectionList, "", SportSelection.All, {}, onFilterSelected = {}, navigateBack = {}) } } \ 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 index fd546aa..a924369 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 @@ -51,10 +51,12 @@ private fun Modifier.highlightsSearchRowModifier(): Modifier = this @Composable fun HighlightsSearchBar( modifier: Modifier = Modifier, - navigateBack: () -> Unit + query: String, + onQueryChange: (String) -> Unit, + navigateBack: () -> Unit, + ) { val interactionSource = remember { MutableInteractionSource() } - var searchQuery by remember { mutableStateOf("") } //todo: to be handled by viewmodel var isFocused by remember { mutableStateOf(true) } val focusManager = LocalFocusManager.current @@ -70,8 +72,8 @@ fun HighlightsSearchBar( modifier = modifier ) { BasicTextField( - value = searchQuery, - onValueChange = { searchQuery = it /*todo viewmodel load results*/ }, + value = query, + onValueChange = onQueryChange, singleLine = true, textStyle = bodyNormal, visualTransformation = VisualTransformation.None, @@ -104,7 +106,7 @@ fun HighlightsSearchBar( ) Box { innerTextField() - if (searchQuery.isEmpty()) { + if (query.isEmpty()) { Text( text = "Search keywords", style = bodyNormal.copy(color = Color.Gray) @@ -114,7 +116,7 @@ fun HighlightsSearchBar( } AnimatedVisibility( - visible = searchQuery.isNotEmpty(), + visible = query.isNotEmpty(), enter = fadeIn() + scaleIn(), exit = fadeOut() + scaleOut() ) { @@ -122,7 +124,7 @@ fun HighlightsSearchBar( painter = painterResource(R.drawable.ic_close), contentDescription = "clear field", modifier = Modifier.clickable( - onClick = { searchQuery = "" } + onClick = { onQueryChange("") } ) ) } @@ -140,7 +142,7 @@ fun HighlightsSearchBar( onClick = { isFocused = false focusManager.clearFocus(force = true) - searchQuery = "" + onQueryChange("") navigateBack() } ) @@ -187,6 +189,8 @@ private fun HighlightsSearchEntryPointRowPreview() { @Composable private fun HighlightsSearchBarPreview() { HighlightsSearchBar( + query = "", + onQueryChange = {}, navigateBack = {} ) } \ 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 4154e77..90f2818 100644 --- a/app/src/main/java/com/cornellappdev/score/screen/HighlightsScreen.kt +++ b/app/src/main/java/com/cornellappdev/score/screen/HighlightsScreen.kt @@ -31,6 +31,7 @@ import com.cornellappdev.score.theme.Style.heading1 import com.cornellappdev.score.util.highlightsList import com.cornellappdev.score.util.sportSelectionList import com.cornellappdev.score.viewmodel.HighlightsViewModel +import kotlinx.coroutines.selects.select import kotlinx.serialization.Serializable @Composable @@ -63,6 +64,7 @@ fun HighlightsScreen( { highlightsViewModel.onRefresh() } ) { HighlightsScreenContent( + selectedSport = uiState.sportSelect, sportList = uiState.sportSelectionList, onSportSelected = { highlightsViewModel.onSportSelected(it) }, todayHighlightsList = uiState.todayHighlights, @@ -83,6 +85,7 @@ enum class HighlightsSubScreenType{ @Composable private fun HighlightsScreenContent( + selectedSport: SportSelection, onSportSelected: (SportSelection) -> Unit, sportList: List = emptyList(), todayHighlightsList: List = emptyList(), @@ -101,7 +104,7 @@ private fun HighlightsScreenContent( HighlightsSearchEntryPointRow(toSearchScreen) } Spacer(modifier = Modifier.height(16.dp)) - HighlightsFilterRow(sportList, onSportSelected) + HighlightsFilterRow(sportList, selectedSport, onSportSelected) Spacer(modifier = Modifier.height(24.dp)) if (todayHighlightsList.isEmpty() && pastThreeHighlightsList.isEmpty()) { EmptyStateBox( @@ -140,6 +143,7 @@ private fun HighlightScreenPreview( ) { ScorePreview { HighlightsScreenContent( + selectedSport = SportSelection.All, sportList = previewData.sportList, todayHighlightsList = previewData.todayHighlightList, pastThreeHighlightsList = previewData.pastHighlightList, diff --git a/app/src/main/java/com/cornellappdev/score/screen/HighlightsSearchScreen.kt b/app/src/main/java/com/cornellappdev/score/screen/HighlightsSearchScreen.kt index 58fb227..9341a14 100644 --- a/app/src/main/java/com/cornellappdev/score/screen/HighlightsSearchScreen.kt +++ b/app/src/main/java/com/cornellappdev/score/screen/HighlightsSearchScreen.kt @@ -26,6 +26,7 @@ import com.cornellappdev.score.util.highlightsList import com.cornellappdev.score.util.recentSearchList import com.cornellappdev.score.util.sportSelectionList import com.cornellappdev.score.viewmodel.HighlightsViewModel +import kotlinx.coroutines.selects.select @Composable @@ -52,7 +53,9 @@ fun HighlightsSearchScreen( onFilterSelected = { highlightsViewModel.onSportSelected(it) }, recentSearchList = emptyList(), /*todo implement in VM*/ highlightsList = highlightsList, - query = "", + query = uiState.query, + selectedFilter = uiState.sportSelect, + onQueryChange = { highlightsViewModel.onQueryChange(it) }, header = header, onItemClick = {}, onCloseClick = {}, @@ -67,12 +70,13 @@ fun HighlightsSearchScreenContent( recentSearchList: List, highlightsList: List, query: String, + selectedFilter: SportSelection, + onQueryChange: (String) -> Unit, header: String, onItemClick: () -> Unit, onCloseClick: () -> Unit, navigateBack: () -> Unit ) { - Column( modifier = Modifier .fillMaxSize() @@ -84,6 +88,9 @@ fun HighlightsSearchScreenContent( Spacer(modifier = Modifier.height(16.dp)) HighlightsScreenSearchFilterBar( sportList, + query, + selectedFilter, + onQueryChange, onFilterSelected, navigateBack ) @@ -123,6 +130,8 @@ private fun HighlightScreenPreview( recentSearchList = previewData.recentSearchList, highlightsList = highlightsList, query = previewData.query, + selectedFilter = SportSelection.All, + onQueryChange = {}, header = "Search All Highlights", onItemClick = {}, onCloseClick = {}, diff --git a/app/src/main/java/com/cornellappdev/score/screen/HighlightsSubScreen.kt b/app/src/main/java/com/cornellappdev/score/screen/HighlightsSubScreen.kt index 59bcbf3..c39700b 100644 --- a/app/src/main/java/com/cornellappdev/score/screen/HighlightsSubScreen.kt +++ b/app/src/main/java/com/cornellappdev/score/screen/HighlightsSubScreen.kt @@ -45,6 +45,7 @@ import com.cornellappdev.score.theme.White import com.cornellappdev.score.util.highlightsList import com.cornellappdev.score.util.sportSelectionList import com.cornellappdev.score.viewmodel.HighlightsViewModel +import kotlinx.coroutines.selects.select @Composable private fun HighlightsSubScreenHeader( @@ -130,6 +131,7 @@ fun HighlightsSubScreen( } HighlightsSubScreenContent( + selectedSport = uiState.sportSelect, sportList = uiState.sportSelectionList, onFilterSelected = { highlightsViewModel.onSportSelected(it) }, highlightsList = highlightsList, @@ -145,6 +147,7 @@ fun HighlightsSubScreen( @Composable fun HighlightsSubScreenContent( + selectedSport: SportSelection, sportList: List, onFilterSelected: (SportSelection) -> Unit, highlightsList: List, @@ -166,7 +169,11 @@ fun HighlightsSubScreenContent( HighlightsSearchEntryPointRow({ toSearchScreen() }) } Spacer(modifier = Modifier.height(16.dp)) - HighlightsFilterRow(sportList, onFilterSelected = onFilterSelected) + HighlightsFilterRow( + sportList, + selectedSport = selectedSport, + onFilterSelected = onFilterSelected + ) Spacer(modifier = Modifier.height(24.dp)) @@ -191,6 +198,7 @@ fun HighlightsSubScreenContent( @Composable private fun HighlightsSubScreenPreview() { HighlightsSubScreenContent( + selectedSport = SportSelection.All, sportList = sportSelectionList, onFilterSelected = {}, highlightsList = highlightsList, diff --git a/app/src/main/java/com/cornellappdev/score/viewmodel/HighlightsViewModel.kt b/app/src/main/java/com/cornellappdev/score/viewmodel/HighlightsViewModel.kt index 280b67b..07311bc 100644 --- a/app/src/main/java/com/cornellappdev/score/viewmodel/HighlightsViewModel.kt +++ b/app/src/main/java/com/cornellappdev/score/viewmodel/HighlightsViewModel.kt @@ -16,37 +16,54 @@ data class HighlightsUiState( val sportSelectionList: List, val filteredHighlights: List, val todayHighlights: List, - val pastThreeDaysHighlights: List + val pastThreeDaysHighlights: List, + val query: String ) private fun buildDerivedLists( highlights: List, - sportSelect: SportSelection + sportSelect: SportSelection, + query: String ): Triple, List, List> { - val today = LocalDate.now() val threeDaysAgo = today.minusDays(3) - // Keep only highlights with a date and matching the sport filter - val validHighlights = highlights + val filteredBySport = highlights .filter { it.date != null } - .filter { highlight -> + .filter { h -> when (sportSelect) { is SportSelection.All -> true - is SportSelection.SportSelect -> - highlight.sport == sportSelect.sport + is SportSelection.SportSelect -> h.sport == sportSelect.sport } } - val filtered = validHighlights.sortedBy { it.date } + val filteredByQuery = + if (query.isBlank()) filteredBySport + else filteredBySport.filter { + it.title.contains(query, ignoreCase = true) || + it.sport?.displayName?.contains(query, ignoreCase = true) ?: false + } + + val sorted = filteredByQuery.sortedByDescending { it.date } + + val todayHighlights = sorted.filter { it.date == today } + + val pastThreeDays = sorted.filter { it.date!! >= threeDaysAgo } - val todayHighlights = validHighlights.filter { it.date == today } + return Triple(sorted, todayHighlights, pastThreeDays) +} + +private fun recompute(highlights: List, state: HighlightsUiState) + : HighlightsUiState { - val pastThreeDaysHighlights = validHighlights - .filter { it.date!! >= threeDaysAgo } // null dates filtered out in line 32 - .sortedBy { it.date } + val (filtered, today, pastThreeDays) = + buildDerivedLists(highlights, state.sportSelect, state.query) - return Triple(filtered, todayHighlights, pastThreeDaysHighlights) + return state.copy( + filteredHighlights = filtered, + todayHighlights = today, + pastThreeDaysHighlights = pastThreeDays + ) } @HiltViewModel @@ -59,7 +76,8 @@ class HighlightsViewModel @Inject constructor( sportSelectionList = Sport.getSportSelectionList(GenderDivision.ALL), filteredHighlights = emptyList(), todayHighlights = emptyList(), - pastThreeDaysHighlights = emptyList() + pastThreeDaysHighlights = emptyList(), + query = "" ) ) { init { @@ -68,17 +86,13 @@ class HighlightsViewModel @Inject constructor( applyMutation { when (response) { is ApiResponse.Success -> { - val sorted = - response.data.sortedByDescending { it.date } + val sorted = response.data.sortedByDescending { it.date } - val (filtered, today, pastThreeDays) = - buildDerivedLists(sorted, sportSelect) - - copy( - loadedState = ApiResponse.Success(sorted), - filteredHighlights = filtered, - todayHighlights = today, - pastThreeDaysHighlights = pastThreeDays + recompute( + sorted, + copy( + loadedState = ApiResponse.Success(sorted) + ) ) } @@ -102,6 +116,17 @@ class HighlightsViewModel @Inject constructor( } } + fun onQueryChange(newQuery: String) { + applyMutation { + val highlights = (loadedState as? ApiResponse.Success)?.data.orEmpty() + + recompute( + highlights, + copy(query = newQuery) + ) + } + } + fun onRefresh() { applyMutation { copy(loadedState = ApiResponse.Loading) @@ -111,19 +136,19 @@ class HighlightsViewModel @Inject constructor( fun onSportSelected(sport: SportSelection) { applyMutation { - val highlights = when (val state = loadedState) { - is ApiResponse.Success -> state.data - else -> emptyList() - } - - val (filtered, today, pastThreeDays) = - buildDerivedLists(highlights, sport) + val highlights = + (loadedState as? ApiResponse.Success)?.data.orEmpty() + + val newSelection = + if (sportSelect == sport) { + SportSelection.All + } else { + sport + } - copy( - sportSelect = sport, - filteredHighlights = filtered, - todayHighlights = today, - pastThreeDaysHighlights = pastThreeDays + recompute( + highlights, + copy(sportSelect = newSelection) ) } } From 1bdddf4e4f2043395a81099f9300b61591591615 Mon Sep 17 00:00:00 2001 From: amjiao Date: Mon, 6 Apr 2026 18:02:40 -0400 Subject: [PATCH 4/6] Recent searches + MVVM refactoring --- .../highlights/HighlightsCardLazyColumn.kt | 47 +++------- .../HighlightsScreenSearchFilterBar.kt | 13 ++- .../highlights/HighlightsSearchBar.kt | 87 +++++++++---------- .../components/highlights/RecentSearches.kt | 12 +-- .../score/screen/HighlightsScreen.kt | 17 ++-- .../score/screen/HighlightsSearchScreen.kt | 45 +++++----- .../score/viewmodel/HighlightsViewModel.kt | 53 ++++++++++- 7 files changed, 150 insertions(+), 124 deletions(-) diff --git a/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsCardLazyColumn.kt b/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsCardLazyColumn.kt index 2a9d968..134fdce 100644 --- a/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsCardLazyColumn.kt +++ b/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsCardLazyColumn.kt @@ -26,49 +26,30 @@ import com.cornellappdev.score.theme.Style.bodyNormal import com.cornellappdev.score.util.highlightsList import com.cornellappdev.score.util.recentSearchList -sealed interface SearchResultsState { - data object Recent : SearchResultsState - data class Results(val items: List) : SearchResultsState - data object Empty : SearchResultsState -} +enum class SearchUiState { RECENT, EMPTY, RESULTS } @Composable fun HighlightsCardLazyColumn( recentSearchList: List, query: String, - highlightsList: List, - onItemClick: () -> Unit, - onCloseClick: () -> Unit, + filteredResults: List, + onItemClick: (String) -> Unit, + onCloseClick: (String) -> Unit, numResultsHeader: (@Composable () -> Unit)? = null ) { Column( modifier = Modifier.padding(horizontal = 24.dp) ) { - /*todo: move to VM*/ - val resultsState: SearchResultsState = - when { - recentSearchList.isNotEmpty() && query.isEmpty() -> - SearchResultsState.Recent - - query.isNotEmpty() -> { - val filtered = highlightsList.filter { - it.title.contains(query, ignoreCase = true) - } - - if (filtered.isEmpty()) { - SearchResultsState.Empty - } else { - SearchResultsState.Results(filtered) - } - } - - else -> SearchResultsState.Recent - } + val uiStateKey = when { + query.isEmpty() -> SearchUiState.RECENT + filteredResults.isEmpty() -> SearchUiState.EMPTY + else -> SearchUiState.RESULTS + } AnimatedContent( - targetState = resultsState, + targetState = uiStateKey, transitionSpec = { (fadeIn() + slideInVertically { it / 8 }) togetherWith (fadeOut() + slideOutVertically { -it / 8 }) @@ -77,7 +58,7 @@ fun HighlightsCardLazyColumn( ) { state -> when (state) { - SearchResultsState.Recent -> { + SearchUiState.RECENT -> { RecentSearches( recentSearchList, onItemClick, @@ -85,21 +66,21 @@ fun HighlightsCardLazyColumn( ) } - SearchResultsState.Empty -> { + SearchUiState.EMPTY -> { EmptyStateBox( icon = R.drawable.ic_kid_star, title = "No results yet." ) } - is SearchResultsState.Results -> { + SearchUiState.RESULTS -> { Column { numResultsHeader?.invoke() LazyColumn( verticalArrangement = Arrangement.spacedBy(16.dp) ) { - items(state.items) { item -> + items(filteredResults) { item -> when (item) { is HighlightData.Video -> VideoHighlightCard(item.data, true) diff --git a/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsScreenSearchFilterBar.kt b/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsScreenSearchFilterBar.kt index 5600e11..130dd74 100644 --- a/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsScreenSearchFilterBar.kt +++ b/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsScreenSearchFilterBar.kt @@ -19,6 +19,7 @@ fun HighlightsScreenSearchFilterBar( query: String, selectedSport: SportSelection, onQueryChange: (String) -> Unit, + onSearch: (String) -> Unit, onFilterSelected: (SportSelection) -> Unit, navigateBack: () -> Unit ) { @@ -27,7 +28,8 @@ fun HighlightsScreenSearchFilterBar( modifier = Modifier.padding(horizontal = 24.dp), query = query, onQueryChange = onQueryChange, - navigateBack + onSearch = onSearch, + navigateBack = navigateBack ) Spacer(modifier = Modifier.height(16.dp)) HighlightsFilterRow(sportList, selectedSport, onFilterSelected) @@ -38,6 +40,13 @@ fun HighlightsScreenSearchFilterBar( @Composable private fun HighlightsScreenSearchFilterBarPreview() { ScorePreview { - HighlightsScreenSearchFilterBar(sportSelectionList, "", SportSelection.All, {}, onFilterSelected = {}, navigateBack = {}) + HighlightsScreenSearchFilterBar( + sportSelectionList, + "", + SportSelection.All, + {}, + {}, + onFilterSelected = {}, + navigateBack = {}) } } \ 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 index a924369..6d1f0c3 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 @@ -16,6 +16,8 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.BasicTextField +import androidx.compose.foundation.text.KeyboardActions +import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -32,7 +34,9 @@ import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.focus.onFocusChanged import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalFocusManager +import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -41,21 +45,23 @@ import com.cornellappdev.score.theme.GrayLight import com.cornellappdev.score.theme.Style.bodyMedium import com.cornellappdev.score.theme.Style.bodyNormal -private fun Modifier.highlightsSearchRowModifier(): Modifier = this - .fillMaxWidth() - .background(Color.White, RoundedCornerShape(100.dp)) - .border(1.dp, GrayLight, RoundedCornerShape(100.dp)) - .clip(RoundedCornerShape(100.dp)) - .padding(horizontal = 8.dp, vertical = 8.dp) +private fun Modifier.highlightsSearchRowModifier(): Modifier = + this + .fillMaxWidth() + .background(Color.White, RoundedCornerShape(100.dp)) + .border(1.dp, GrayLight, RoundedCornerShape(100.dp)) + .clip(RoundedCornerShape(100.dp)) + .padding(horizontal = 8.dp, vertical = 8.dp) @Composable fun HighlightsSearchBar( - modifier: Modifier = Modifier, query: String, onQueryChange: (String) -> Unit, - navigateBack: () -> Unit, - + onSearch: (String) -> Unit, + modifier: Modifier = Modifier, + navigateBack: () -> Unit ) { + val keyboardController = LocalSoftwareKeyboardController.current val interactionSource = remember { MutableInteractionSource() } var isFocused by remember { mutableStateOf(true) } @@ -79,6 +85,15 @@ fun HighlightsSearchBar( visualTransformation = VisualTransformation.None, interactionSource = interactionSource, enabled = true, + keyboardOptions = KeyboardOptions( + imeAction = ImeAction.Search + ), + keyboardActions = KeyboardActions( + onSearch = { + onSearch(query) + keyboardController?.hide() + focusManager.clearFocus() + }), modifier = Modifier .focusRequester(focusRequester) .weight(1f) @@ -89,9 +104,7 @@ fun HighlightsSearchBar( }, decorationBox = { innerTextField -> Row( - modifier = - Modifier - .highlightsSearchRowModifier(), + modifier = Modifier.highlightsSearchRowModifier(), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.SpaceBetween ) { @@ -124,29 +137,22 @@ fun HighlightsSearchBar( painter = painterResource(R.drawable.ic_close), contentDescription = "clear field", modifier = Modifier.clickable( - onClick = { onQueryChange("") } - ) - ) + onClick = { onQueryChange("") })) } } - } - ) + }) AnimatedVisibility( isFocused ) { Text( - "Cancel", - style = bodyMedium, - modifier = Modifier.clickable( - onClick = { - isFocused = false - focusManager.clearFocus(force = true) - onQueryChange("") - navigateBack() - } - ) - ) + "Cancel", style = bodyMedium, modifier = Modifier.clickable( + onClick = { + isFocused = false + focusManager.clearFocus(force = true) + onQueryChange("") + navigateBack() + })) } } } @@ -154,18 +160,14 @@ fun HighlightsSearchBar( /*HighlightsSearchEntryPointRow is the non-functional version of the HighlightsSearchBar, it's a dummy component that's clickable in HighlightsScreen and will navigate to HighlightsSearchScreen */ @Composable fun HighlightsSearchEntryPointRow( - onClick: () -> Unit, - modifier: Modifier = Modifier + onClick: () -> Unit, modifier: Modifier = Modifier ) { - Row( - modifier = - Modifier - .highlightsSearchRowModifier() - .clickable { onClick() } - .then(modifier), + Row(modifier = Modifier + .highlightsSearchRowModifier() + .clickable { onClick() } + .then(modifier), verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(4.dp) - ) { + horizontalArrangement = Arrangement.spacedBy(4.dp)) { Icon( painter = painterResource(R.drawable.search), contentDescription = "search icon", @@ -173,8 +175,7 @@ fun HighlightsSearchEntryPointRow( ) Text( - text = "Search keywords", - style = bodyNormal.copy(color = Color.Gray) + text = "Search keywords", style = bodyNormal.copy(color = Color.Gray) ) } } @@ -188,9 +189,5 @@ private fun HighlightsSearchEntryPointRowPreview() { @Preview @Composable private fun HighlightsSearchBarPreview() { - HighlightsSearchBar( - query = "", - onQueryChange = {}, - navigateBack = {} - ) + HighlightsSearchBar(query = "", onQueryChange = {}, onSearch = {}, navigateBack = {}) } \ No newline at end of file diff --git a/app/src/main/java/com/cornellappdev/score/components/highlights/RecentSearches.kt b/app/src/main/java/com/cornellappdev/score/components/highlights/RecentSearches.kt index 460c37a..123bcc2 100644 --- a/app/src/main/java/com/cornellappdev/score/components/highlights/RecentSearches.kt +++ b/app/src/main/java/com/cornellappdev/score/components/highlights/RecentSearches.kt @@ -25,15 +25,15 @@ import com.cornellappdev.score.theme.Style.metricSmallNormal @Composable private fun RecentSearchItem( query: String, - onItemClick: () -> Unit, - onCloseClick: () -> Unit + onItemClick: (String) -> Unit, + onCloseClick: (String) -> Unit ) { Row( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.SpaceBetween, modifier = Modifier .fillMaxWidth() - .clickable(onClick = { onItemClick() /*search the query*/ }) + .clickable(onClick = { onItemClick(query) /*search the query*/ }) ) { Row( verticalAlignment = Alignment.CenterVertically, @@ -48,7 +48,7 @@ private fun RecentSearchItem( } IconButton( - onClick = { onCloseClick() /*delete this search from the recent searches list*/ }, + onClick = { onCloseClick(query) /*delete this search from the recent searches list*/ }, modifier = Modifier.size(10.dp) ) { Icon( @@ -63,8 +63,8 @@ private fun RecentSearchItem( @Composable fun RecentSearches( recentQueriesList: List, - onItemClick: () -> Unit, - onCloseClick: () -> Unit + onItemClick: (String) -> Unit, + onCloseClick: (String) -> Unit ) { Column( modifier = Modifier 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 90f2818..779e250 100644 --- a/app/src/main/java/com/cornellappdev/score/screen/HighlightsScreen.kt +++ b/app/src/main/java/com/cornellappdev/score/screen/HighlightsScreen.kt @@ -31,7 +31,6 @@ import com.cornellappdev.score.theme.Style.heading1 import com.cornellappdev.score.util.highlightsList import com.cornellappdev.score.util.sportSelectionList import com.cornellappdev.score.viewmodel.HighlightsViewModel -import kotlinx.coroutines.selects.select import kotlinx.serialization.Serializable @Composable @@ -61,8 +60,7 @@ fun HighlightsScreen( is ApiResponse.Success -> { ScorePullToRefreshBox( isRefreshing = uiState.loadedState == ApiResponse.Loading, - { highlightsViewModel.onRefresh() } - ) { + { highlightsViewModel.onRefresh() }) { HighlightsScreenContent( selectedSport = uiState.sportSelect, sportList = uiState.sportSelectionList, @@ -79,7 +77,7 @@ fun HighlightsScreen( } @Serializable -enum class HighlightsSubScreenType{ +enum class HighlightsSubScreenType { TODAY, PAST3DAYS, ALL } @@ -87,9 +85,9 @@ enum class HighlightsSubScreenType{ private fun HighlightsScreenContent( selectedSport: SportSelection, onSportSelected: (SportSelection) -> Unit, - sportList: List = emptyList(), - todayHighlightsList: List = emptyList(), - pastThreeHighlightsList: List = emptyList(), + sportList: List, + todayHighlightsList: List, + pastThreeHighlightsList: List, toSearchScreen: () -> Unit, toSubScreen: (HighlightsSubScreenType) -> Unit ) { @@ -113,7 +111,7 @@ private fun HighlightsScreenContent( ) } if (todayHighlightsList.isNotEmpty()) { - HighlightsCardRow(todayHighlightsList, "Today", toSubScreen ) + HighlightsCardRow(todayHighlightsList, "Today", toSubScreen) } if (pastThreeHighlightsList.isNotEmpty()) { HighlightsCardRow(pastThreeHighlightsList, "Past 3 days", toSubScreen) @@ -149,7 +147,6 @@ private fun HighlightScreenPreview( pastThreeHighlightsList = previewData.pastHighlightList, toSearchScreen = {}, onSportSelected = {}, - toSubScreen = {} - ) + toSubScreen = {}) } } \ No newline at end of file diff --git a/app/src/main/java/com/cornellappdev/score/screen/HighlightsSearchScreen.kt b/app/src/main/java/com/cornellappdev/score/screen/HighlightsSearchScreen.kt index 9341a14..c297083 100644 --- a/app/src/main/java/com/cornellappdev/score/screen/HighlightsSearchScreen.kt +++ b/app/src/main/java/com/cornellappdev/score/screen/HighlightsSearchScreen.kt @@ -26,7 +26,6 @@ import com.cornellappdev.score.util.highlightsList import com.cornellappdev.score.util.recentSearchList import com.cornellappdev.score.util.sportSelectionList import com.cornellappdev.score.viewmodel.HighlightsViewModel -import kotlinx.coroutines.selects.select @Composable @@ -37,28 +36,24 @@ fun HighlightsSearchScreen( ) { val uiState = highlightsViewModel.collectUiStateValue() - val (highlightsList, header) = when (searchScreenType) { - HighlightsSubScreenType.TODAY -> - uiState.todayHighlights to "Search today" - - HighlightsSubScreenType.PAST3DAYS -> - uiState.pastThreeDaysHighlights to "Search past 3 days" - - HighlightsSubScreenType.ALL -> - uiState.filteredHighlights to "Search all highlights" + val header = when (searchScreenType) { + HighlightsSubScreenType.TODAY -> "Search today" + HighlightsSubScreenType.PAST3DAYS -> "Search past 3 days" + HighlightsSubScreenType.ALL -> "Search all highlights" } HighlightsSearchScreenContent( sportList = uiState.sportSelectionList, onFilterSelected = { highlightsViewModel.onSportSelected(it) }, - recentSearchList = emptyList(), /*todo implement in VM*/ - highlightsList = highlightsList, + recentSearchList = uiState.recentSearches, + filteredResults = uiState.filteredHighlights, query = uiState.query, selectedFilter = uiState.sportSelect, onQueryChange = { highlightsViewModel.onQueryChange(it) }, + onSearch = { highlightsViewModel.onSearch(it) }, header = header, - onItemClick = {}, - onCloseClick = {}, + onItemClick = { highlightsViewModel.onSearchRecent(it) }, + onCloseClick = { highlightsViewModel.onRemoveRecent(it) }, navigateBack = navigateBack ) } @@ -68,13 +63,14 @@ fun HighlightsSearchScreenContent( sportList: List, onFilterSelected: (SportSelection) -> Unit, recentSearchList: List, - highlightsList: List, + filteredResults: List, query: String, selectedFilter: SportSelection, onQueryChange: (String) -> Unit, + onSearch: (String) -> Unit, header: String, - onItemClick: () -> Unit, - onCloseClick: () -> Unit, + onItemClick: (String) -> Unit, + onCloseClick: (String) -> Unit, navigateBack: () -> Unit ) { Column( @@ -91,6 +87,7 @@ fun HighlightsSearchScreenContent( query, selectedFilter, onQueryChange, + onSearch, onFilterSelected, navigateBack ) @@ -98,15 +95,15 @@ fun HighlightsSearchScreenContent( HighlightsCardLazyColumn( recentSearchList, query, - highlightsList, onItemClick, onCloseClick, + filteredResults, + onItemClick, + onCloseClick, { HighlightsCardLazyColumnResultsHeader(highlightsList.size) }) } } data class HighlightsSearchScreenPreviewData( - val sportList: List, - val recentSearchList: List, - val query: String + val sportList: List, val recentSearchList: List, val query: String ) class HighlightsSearchScreenPreviewProvider : @@ -128,14 +125,14 @@ private fun HighlightScreenPreview( sportList = previewData.sportList, onFilterSelected = {}, recentSearchList = previewData.recentSearchList, - highlightsList = highlightsList, + filteredResults = highlightsList, query = previewData.query, selectedFilter = SportSelection.All, onQueryChange = {}, + onSearch = {}, header = "Search All Highlights", onItemClick = {}, onCloseClick = {}, - navigateBack = {} - ) + navigateBack = {}) } } \ No newline at end of file diff --git a/app/src/main/java/com/cornellappdev/score/viewmodel/HighlightsViewModel.kt b/app/src/main/java/com/cornellappdev/score/viewmodel/HighlightsViewModel.kt index 07311bc..b27429e 100644 --- a/app/src/main/java/com/cornellappdev/score/viewmodel/HighlightsViewModel.kt +++ b/app/src/main/java/com/cornellappdev/score/viewmodel/HighlightsViewModel.kt @@ -7,6 +7,10 @@ import com.cornellappdev.score.model.HighlightsRepository import com.cornellappdev.score.model.Sport import com.cornellappdev.score.model.SportSelection import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.FlowPreview +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.debounce import java.time.LocalDate import javax.inject.Inject @@ -17,7 +21,8 @@ data class HighlightsUiState( val filteredHighlights: List, val todayHighlights: List, val pastThreeDaysHighlights: List, - val query: String + val query: String, + val recentSearches: List ) private fun buildDerivedLists( @@ -41,14 +46,18 @@ private fun buildDerivedLists( if (query.isBlank()) filteredBySport else filteredBySport.filter { it.title.contains(query, ignoreCase = true) || - it.sport?.displayName?.contains(query, ignoreCase = true) ?: false + (it.sport?.displayName?.contains(query, ignoreCase = true) == true) } val sorted = filteredByQuery.sortedByDescending { it.date } val todayHighlights = sorted.filter { it.date == today } - val pastThreeDays = sorted.filter { it.date!! >= threeDaysAgo } + val pastThreeDays = sorted.filter { date -> + date.date?.let { + it < today && it >= threeDaysAgo + } ?: false + } return Triple(sorted, todayHighlights, pastThreeDays) } @@ -77,7 +86,8 @@ class HighlightsViewModel @Inject constructor( filteredHighlights = emptyList(), todayHighlights = emptyList(), pastThreeDaysHighlights = emptyList(), - query = "" + query = "", + recentSearches = emptyList() ) ) { init { @@ -152,4 +162,39 @@ class HighlightsViewModel @Inject constructor( ) } } + + fun onSearch(query: String) { + if (query.isBlank()) return + + applyMutation { + val highlights = + (loadedState as? ApiResponse.Success)?.data.orEmpty() + + val updatedSearches = + (listOf(query) + recentSearches) + .distinct() + .take(3) + + recompute( + highlights, + copy( + query = query, + recentSearches = updatedSearches + ) + ) + } + } + + //Removes an item from the recent searches list + fun onRemoveRecent(recent: String) { + applyMutation { + val updated = recentSearches.filterNot { it == recent } + copy(recentSearches = updated) + } + } + + //Searches an item from the recent searches list + fun onSearchRecent(recent: String) { + onSearch(recent) + } } From b52001f9480bbbf0d4072b184cb9de3a68cc2ce0 Mon Sep 17 00:00:00 2001 From: amjiao Date: Wed, 22 Apr 2026 11:18:56 -0400 Subject: [PATCH 5/6] Add loading screens --- .../highlights/HighlightsLoadingScreen.kt | 202 ++++++++++++++++++ .../score/screen/HighlightsScreen.kt | 4 +- .../score/screen/HighlightsSubScreen.kt | 32 ++- 3 files changed, 219 insertions(+), 19 deletions(-) create mode 100644 app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsLoadingScreen.kt diff --git a/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsLoadingScreen.kt b/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsLoadingScreen.kt new file mode 100644 index 0000000..6b6db98 --- /dev/null +++ b/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsLoadingScreen.kt @@ -0,0 +1,202 @@ +package com.cornellappdev.score.components.highlights + +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.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.cornellappdev.score.screen.HighlightsSubScreenHeader +import com.cornellappdev.score.theme.GrayStroke +import com.cornellappdev.score.theme.Style.heading1 +import com.cornellappdev.score.theme.Style.heading2 + +@Composable +fun HighlightsLoadingScreen( + topHeader: String, + modifier: Modifier = Modifier +) { + Column( + modifier = modifier.fillMaxSize() + ) { + Column( + modifier = Modifier.padding(horizontal = 24.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text( + text = topHeader, + style = heading1, + color = GrayStroke, + modifier = Modifier + .fillMaxWidth() + .align(Alignment.Start) + ) + Spacer(modifier = Modifier.height(16.dp)) + _root_ide_package_.com.cornellappdev.score.components.LoadingStateBox(100, 40.dp) + } + Spacer(modifier = Modifier.height(16.dp)) + Row( + modifier = Modifier.padding(start = 24.dp), + horizontalArrangement = Arrangement.spacedBy(12.dp), + ) { + for (i in 0 until 4) { + _root_ide_package_.com.cornellappdev.score.components.LoadingStateBox( + 100, + 30.dp, + modifier = Modifier.width(85.dp) + ) + } + } + Spacer(modifier = Modifier.height(24.dp)) + Row( + modifier = Modifier + .padding(horizontal = 24.dp) + .fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "Loading Today...", + style = heading2, + color = GrayStroke + ) + _root_ide_package_.com.cornellappdev.score.components.LoadingStateBox( + 100, 15.dp, modifier = Modifier.width( + 50 + .dp + ) + ) + } + Spacer(modifier = Modifier.height(16.dp)) + Row( + modifier = Modifier.padding(start = 24.dp), + horizontalArrangement = Arrangement.spacedBy(16.dp) + ) { + _root_ide_package_.com.cornellappdev.score.components.LoadingStateBox( + 12, 192.dp, modifier = Modifier.width( + 241 + .dp + ) + ) + _root_ide_package_.com.cornellappdev.score.components.LoadingStateBox( + 12, 192.dp, modifier = Modifier.width( + 241 + .dp + ) + ) + } + Spacer(modifier = Modifier.height(24.dp)) + Row( + modifier = Modifier + .padding(horizontal = 24.dp) + .fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "Loading Past 3 Days...", + style = heading2, + color = GrayStroke + ) + _root_ide_package_.com.cornellappdev.score.components.LoadingStateBox( + 100, 15.dp, modifier = Modifier.width( + 50 + .dp + ) + ) + } + Spacer(modifier = Modifier.height(16.dp)) + Row( + modifier = Modifier.padding(start = 24.dp), + horizontalArrangement = Arrangement.spacedBy(16.dp) + ) { + _root_ide_package_.com.cornellappdev.score.components.LoadingStateBox( + 12, 192.dp, modifier = Modifier.width( + 241 + .dp + ) + ) + _root_ide_package_.com.cornellappdev.score.components.LoadingStateBox( + 12, 192.dp, modifier = Modifier.width( + 241 + .dp + ) + ) + } + } +} + +@Composable +fun SubHighlightsLoadingScreen( + header: String, + modifier: Modifier = Modifier +) { + Column( + modifier = Modifier.fillMaxWidth() + ) { + HighlightsSubScreenHeader( + header = header, + navigateBack = {} + ) + Column( + modifier = modifier + .fillMaxWidth() + .padding(start = 24.dp, end = 24.dp, top = 24.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + _root_ide_package_.com.cornellappdev.score.components.LoadingStateBox( + 100, + height = 40.dp + ) + + Spacer(modifier = Modifier.height(16.dp)) + } + Row( + modifier = Modifier.padding(start = 24.dp), + horizontalArrangement = Arrangement.spacedBy(12.dp), + ) { + for (i in 0 until 4) { + _root_ide_package_.com.cornellappdev.score.components.LoadingStateBox( + 100, + 30.dp, + modifier = Modifier.width(85.dp) + ) + } + } + Spacer(modifier.height(24.dp)) + Column( + modifier = Modifier.padding(horizontal = 24.dp), + verticalArrangement = Arrangement.spacedBy(16.dp) + ) { + for (i in 0 until 4) { + _root_ide_package_.com.cornellappdev.score.components.LoadingStateBox( + 12, 192.dp + ) + } + } + } +} + + +@Preview +@Composable +private fun HighlightsLoadingScreenPreview() = + _root_ide_package_.com.cornellappdev.score.components.ScorePreview { + HighlightsLoadingScreen("Loading Highlights...") + } + +@Preview +@Composable +private fun SubHighlightsLoadingScreenPreview() = + _root_ide_package_.com.cornellappdev.score.components.ScorePreview { + SubHighlightsLoadingScreen("Past 3 Days") + } \ 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 779e250..87706a9 100644 --- a/app/src/main/java/com/cornellappdev/score/screen/HighlightsScreen.kt +++ b/app/src/main/java/com/cornellappdev/score/screen/HighlightsScreen.kt @@ -18,6 +18,7 @@ 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.highlights.HighlightsLoadingScreen import com.cornellappdev.score.components.LoadingScreen import com.cornellappdev.score.components.ScorePreview import com.cornellappdev.score.components.ScorePullToRefreshBox @@ -49,8 +50,7 @@ fun HighlightsScreen( ) { when (uiState.loadedState) { is ApiResponse.Loading -> { - //todo make highlights loading screen, this one's for the home page - LoadingScreen("Loading Highlights...", "Loading Schedules...") + HighlightsLoadingScreen("Loading Highlights...") } is ApiResponse.Error -> { diff --git a/app/src/main/java/com/cornellappdev/score/screen/HighlightsSubScreen.kt b/app/src/main/java/com/cornellappdev/score/screen/HighlightsSubScreen.kt index c39700b..3e309b4 100644 --- a/app/src/main/java/com/cornellappdev/score/screen/HighlightsSubScreen.kt +++ b/app/src/main/java/com/cornellappdev/score/screen/HighlightsSubScreen.kt @@ -30,12 +30,12 @@ import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import com.cornellappdev.score.R import com.cornellappdev.score.components.ErrorState -import com.cornellappdev.score.components.LoadingScreen import com.cornellappdev.score.components.ScorePreview import com.cornellappdev.score.components.ScorePullToRefreshBox import com.cornellappdev.score.components.highlights.ArticleHighlightCard import com.cornellappdev.score.components.highlights.HighlightsFilterRow import com.cornellappdev.score.components.highlights.HighlightsSearchEntryPointRow +import com.cornellappdev.score.components.highlights.SubHighlightsLoadingScreen import com.cornellappdev.score.components.highlights.VideoHighlightCard import com.cornellappdev.score.model.ApiResponse import com.cornellappdev.score.model.HighlightData @@ -45,10 +45,9 @@ import com.cornellappdev.score.theme.White import com.cornellappdev.score.util.highlightsList import com.cornellappdev.score.util.sportSelectionList import com.cornellappdev.score.viewmodel.HighlightsViewModel -import kotlinx.coroutines.selects.select @Composable -private fun HighlightsSubScreenHeader( +fun HighlightsSubScreenHeader( header: String, navigateBack: () -> Unit ) { @@ -104,10 +103,20 @@ fun HighlightsSubScreen( .fillMaxSize() .background(color = Color.White) ) { + val (highlightsList, header) = when (subScreenType) { + HighlightsSubScreenType.TODAY -> + uiState.todayHighlights to "Today" + + HighlightsSubScreenType.PAST3DAYS -> + uiState.pastThreeDaysHighlights to "Past 3 Days" + + HighlightsSubScreenType.ALL -> + uiState.filteredHighlights to "All highlights" + } + when (uiState.loadedState) { is ApiResponse.Loading -> { - //todo make highlights loading screen, this one's for the home page - LoadingScreen("Loading Highlights...", "Loading Schedules...") + SubHighlightsLoadingScreen(header) } is ApiResponse.Error -> { @@ -119,17 +128,6 @@ fun HighlightsSubScreen( isRefreshing = uiState.loadedState == ApiResponse.Loading, { highlightsViewModel.onRefresh() } ) { - val (highlightsList, header) = when (subScreenType) { - HighlightsSubScreenType.TODAY -> - uiState.todayHighlights to "Today" - - HighlightsSubScreenType.PAST3DAYS -> - uiState.pastThreeDaysHighlights to "Past 3 Days" - - HighlightsSubScreenType.ALL -> - uiState.filteredHighlights to "All highlights" - } - HighlightsSubScreenContent( selectedSport = uiState.sportSelect, sportList = uiState.sportSelectionList, @@ -159,7 +157,7 @@ fun HighlightsSubScreenContent( modifier = Modifier .fillMaxSize() .background(color = Color.White) - .padding(top = 24.dp) + //.padding(top = 24.dp) ) { HighlightsSubScreenHeader(header, navigateBack) Spacer(modifier = Modifier.height(24.dp)) From 86b8ace5a662c1be6173bc78007d2a2087df128a Mon Sep 17 00:00:00 2001 From: amjiao Date: Wed, 22 Apr 2026 15:05:59 -0400 Subject: [PATCH 6/6] fix imports --- .../highlights/HighlightsLoadingScreen.kt | 76 +++++++------------ 1 file changed, 29 insertions(+), 47 deletions(-) diff --git a/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsLoadingScreen.kt b/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsLoadingScreen.kt index 6b6db98..0d10eb2 100644 --- a/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsLoadingScreen.kt +++ b/app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsLoadingScreen.kt @@ -15,6 +15,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import com.cornellappdev.score.components.LoadingStateBox import com.cornellappdev.score.screen.HighlightsSubScreenHeader import com.cornellappdev.score.theme.GrayStroke import com.cornellappdev.score.theme.Style.heading1 @@ -22,8 +23,7 @@ import com.cornellappdev.score.theme.Style.heading2 @Composable fun HighlightsLoadingScreen( - topHeader: String, - modifier: Modifier = Modifier + topHeader: String, modifier: Modifier = Modifier ) { Column( modifier = modifier.fillMaxSize() @@ -41,18 +41,16 @@ fun HighlightsLoadingScreen( .align(Alignment.Start) ) Spacer(modifier = Modifier.height(16.dp)) - _root_ide_package_.com.cornellappdev.score.components.LoadingStateBox(100, 40.dp) + LoadingStateBox(100, 40.dp) } Spacer(modifier = Modifier.height(16.dp)) Row( modifier = Modifier.padding(start = 24.dp), horizontalArrangement = Arrangement.spacedBy(12.dp), ) { - for (i in 0 until 4) { - _root_ide_package_.com.cornellappdev.score.components.LoadingStateBox( - 100, - 30.dp, - modifier = Modifier.width(85.dp) + repeat(4) { + LoadingStateBox( + 100, 30.dp, modifier = Modifier.width(85.dp) ) } } @@ -65,14 +63,11 @@ fun HighlightsLoadingScreen( verticalAlignment = Alignment.CenterVertically ) { Text( - text = "Loading Today...", - style = heading2, - color = GrayStroke + text = "Loading Today...", style = heading2, color = GrayStroke ) - _root_ide_package_.com.cornellappdev.score.components.LoadingStateBox( + LoadingStateBox( 100, 15.dp, modifier = Modifier.width( - 50 - .dp + 50.dp ) ) } @@ -81,16 +76,14 @@ fun HighlightsLoadingScreen( modifier = Modifier.padding(start = 24.dp), horizontalArrangement = Arrangement.spacedBy(16.dp) ) { - _root_ide_package_.com.cornellappdev.score.components.LoadingStateBox( + LoadingStateBox( 12, 192.dp, modifier = Modifier.width( - 241 - .dp + 241.dp ) ) - _root_ide_package_.com.cornellappdev.score.components.LoadingStateBox( + LoadingStateBox( 12, 192.dp, modifier = Modifier.width( - 241 - .dp + 241.dp ) ) } @@ -103,14 +96,11 @@ fun HighlightsLoadingScreen( verticalAlignment = Alignment.CenterVertically ) { Text( - text = "Loading Past 3 Days...", - style = heading2, - color = GrayStroke + text = "Loading Past 3 Days...", style = heading2, color = GrayStroke ) - _root_ide_package_.com.cornellappdev.score.components.LoadingStateBox( + LoadingStateBox( 100, 15.dp, modifier = Modifier.width( - 50 - .dp + 50.dp ) ) } @@ -119,16 +109,14 @@ fun HighlightsLoadingScreen( modifier = Modifier.padding(start = 24.dp), horizontalArrangement = Arrangement.spacedBy(16.dp) ) { - _root_ide_package_.com.cornellappdev.score.components.LoadingStateBox( + LoadingStateBox( 12, 192.dp, modifier = Modifier.width( - 241 - .dp + 241.dp ) ) - _root_ide_package_.com.cornellappdev.score.components.LoadingStateBox( + LoadingStateBox( 12, 192.dp, modifier = Modifier.width( - 241 - .dp + 241.dp ) ) } @@ -137,25 +125,21 @@ fun HighlightsLoadingScreen( @Composable fun SubHighlightsLoadingScreen( - header: String, - modifier: Modifier = Modifier + header: String, modifier: Modifier = Modifier ) { Column( modifier = Modifier.fillMaxWidth() ) { HighlightsSubScreenHeader( - header = header, - navigateBack = {} - ) + header = header, navigateBack = {}) Column( modifier = modifier .fillMaxWidth() .padding(start = 24.dp, end = 24.dp, top = 24.dp), horizontalAlignment = Alignment.CenterHorizontally ) { - _root_ide_package_.com.cornellappdev.score.components.LoadingStateBox( - 100, - height = 40.dp + LoadingStateBox( + 100, height = 40.dp ) Spacer(modifier = Modifier.height(16.dp)) @@ -164,11 +148,9 @@ fun SubHighlightsLoadingScreen( modifier = Modifier.padding(start = 24.dp), horizontalArrangement = Arrangement.spacedBy(12.dp), ) { - for (i in 0 until 4) { - _root_ide_package_.com.cornellappdev.score.components.LoadingStateBox( - 100, - 30.dp, - modifier = Modifier.width(85.dp) + repeat(4) { + LoadingStateBox( + 100, 30.dp, modifier = Modifier.width(85.dp) ) } } @@ -177,8 +159,8 @@ fun SubHighlightsLoadingScreen( modifier = Modifier.padding(horizontal = 24.dp), verticalArrangement = Arrangement.spacedBy(16.dp) ) { - for (i in 0 until 4) { - _root_ide_package_.com.cornellappdev.score.components.LoadingStateBox( + repeat(4) { + LoadingStateBox( 12, 192.dp ) }