Skip to content

Commit fd54480

Browse files
authored
Merge highlights networking branches (#108)
* Set up navigation between highlights screens * Small style/user flow fixes * refactor query and filtering functionality to VM * Recent searches + MVVM refactoring * Add loading screens * fix imports
1 parent de8f4cd commit fd54480

13 files changed

Lines changed: 634 additions & 205 deletions

app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsCardLazyColumn.kt

Lines changed: 14 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -26,49 +26,30 @@ import com.cornellappdev.score.theme.Style.bodyNormal
2626
import com.cornellappdev.score.util.highlightsList
2727
import com.cornellappdev.score.util.recentSearchList
2828

29-
sealed interface SearchResultsState {
30-
data object Recent : SearchResultsState
31-
data class Results(val items: List<HighlightData>) : SearchResultsState
32-
data object Empty : SearchResultsState
33-
}
29+
enum class SearchUiState { RECENT, EMPTY, RESULTS }
3430

3531
@Composable
3632
fun HighlightsCardLazyColumn(
3733
recentSearchList: List<String>,
3834
query: String,
39-
highlightsList: List<HighlightData>,
40-
onItemClick: () -> Unit,
41-
onCloseClick: () -> Unit,
35+
filteredResults: List<HighlightData>,
36+
onItemClick: (String) -> Unit,
37+
onCloseClick: (String) -> Unit,
4238
numResultsHeader: (@Composable () -> Unit)? = null
4339
) {
4440

4541
Column(
4642
modifier = Modifier.padding(horizontal = 24.dp)
4743
) {
48-
/*todo: move to VM*/
49-
val resultsState: SearchResultsState =
50-
when {
51-
recentSearchList.isNotEmpty() && query.isEmpty() ->
52-
SearchResultsState.Recent
53-
54-
query.isNotEmpty() -> {
55-
val filtered = highlightsList.filter {
56-
it.title.contains(query, ignoreCase = true)
57-
}
58-
59-
if (filtered.isEmpty()) {
60-
SearchResultsState.Empty
61-
} else {
62-
SearchResultsState.Results(filtered)
63-
}
64-
}
65-
66-
else -> SearchResultsState.Recent
67-
}
6844

45+
val uiStateKey = when {
46+
query.isEmpty() -> SearchUiState.RECENT
47+
filteredResults.isEmpty() -> SearchUiState.EMPTY
48+
else -> SearchUiState.RESULTS
49+
}
6950

7051
AnimatedContent(
71-
targetState = resultsState,
52+
targetState = uiStateKey,
7253
transitionSpec = {
7354
(fadeIn() + slideInVertically { it / 8 }) togetherWith
7455
(fadeOut() + slideOutVertically { -it / 8 })
@@ -77,29 +58,29 @@ fun HighlightsCardLazyColumn(
7758
) { state ->
7859

7960
when (state) {
80-
SearchResultsState.Recent -> {
61+
SearchUiState.RECENT -> {
8162
RecentSearches(
8263
recentSearchList,
8364
onItemClick,
8465
onCloseClick
8566
)
8667
}
8768

88-
SearchResultsState.Empty -> {
69+
SearchUiState.EMPTY -> {
8970
EmptyStateBox(
9071
icon = R.drawable.ic_kid_star,
9172
title = "No results yet."
9273
)
9374
}
9475

95-
is SearchResultsState.Results -> {
76+
SearchUiState.RESULTS -> {
9677
Column {
9778
numResultsHeader?.invoke()
9879

9980
LazyColumn(
10081
verticalArrangement = Arrangement.spacedBy(16.dp)
10182
) {
102-
items(state.items) { item ->
83+
items(filteredResults) { item ->
10384
when (item) {
10485
is HighlightData.Video ->
10586
VideoHighlightCard(item.data, true)

app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsCardRow.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,16 @@ import androidx.compose.ui.unit.dp
2323
import com.cornellappdev.score.R
2424
import com.cornellappdev.score.components.ScorePreview
2525
import com.cornellappdev.score.model.HighlightData
26+
import com.cornellappdev.score.screen.HighlightsSubScreenType
2627
import com.cornellappdev.score.theme.Style.bodyNormal
2728
import com.cornellappdev.score.theme.Style.heading2
2829
import com.cornellappdev.score.util.highlightsList
2930

3031
@Composable
3132
fun HighlightsCardRow(
3233
highlightsList: List<HighlightData>,
33-
rowHeader: String
34+
rowHeader: String,
35+
toSubScreen: (HighlightsSubScreenType) -> Unit
3436
) {
3537
Column(
3638
modifier = Modifier.fillMaxWidth()
@@ -47,7 +49,7 @@ fun HighlightsCardRow(
4749
style = heading2
4850
)
4951
Row(
50-
modifier = Modifier.clickable {/*todo navigation to Today screen*/ },
52+
modifier = Modifier.clickable { toSubScreen(if (rowHeader == "Today") HighlightsSubScreenType.TODAY else HighlightsSubScreenType.PAST3DAYS) },
5153
verticalAlignment = Alignment.CenterVertically
5254
) {
5355
Text(
@@ -82,6 +84,6 @@ fun HighlightsCardRow(
8284
@Composable
8385
private fun HighlightsCardRowPreview() {
8486
ScorePreview {
85-
HighlightsCardRow(highlightsList, "Today")
87+
HighlightsCardRow(highlightsList, "Today", {})
8688
}
8789
}

app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsFilter.kt

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ import com.cornellappdev.score.theme.GrayPrimary
3333
import com.cornellappdev.score.theme.Stroke
3434
import com.cornellappdev.score.theme.Style.bodyNormal
3535
import com.cornellappdev.score.theme.White
36-
import com.cornellappdev.score.util.sportList
3736
import com.cornellappdev.score.util.sportSelectionList
3837

3938
@Composable
@@ -50,7 +49,8 @@ private fun HighlightsFilterButton(
5049
shape = RoundedCornerShape(100.dp),
5150
colors = outlinedButtonColors(
5251
containerColor = if (isSelected) GrayLight else White,
53-
contentColor = GrayPrimary
52+
contentColor = GrayPrimary,
53+
disabledContainerColor = GrayLight
5454
),
5555
contentPadding = PaddingValues(horizontal = 12.dp, vertical = 4.dp),
5656
) {
@@ -70,6 +70,7 @@ private fun HighlightsFilterButton(
7070
@Composable
7171
fun HighlightsFilterRow(
7272
sportList: List<SportSelection>,
73+
selectedSport: SportSelection,
7374
onFilterSelected: (SportSelection) -> Unit,
7475
) {
7576
LazyRow(
@@ -82,24 +83,27 @@ fun HighlightsFilterRow(
8283
items = sportList.filterIsInstance<SportSelection.SportSelect>(),
8384
key = { it.sport }
8485
) { selection ->
86+
87+
val isSelected = selectedSport == selection
88+
8589
HighlightsFilterButton(
8690
sport = selection.sport,
87-
onFilterSelected = onFilterSelected
91+
onFilterSelected = onFilterSelected,
92+
isSelected = isSelected
8893
)
8994
}
9095
}
91-
9296
}
9397

9498
@Preview
9599
@Composable
96100
private fun HighlightsFilterButtonPreview() {
97101
var isSelected by remember { mutableStateOf(false) }
98-
HighlightsFilterButton(Sport.BASEBALL, { isSelected = !isSelected }, isSelected = isSelected)
102+
HighlightsFilterButton(Sport.BASEBALL, { !isSelected }, isSelected = isSelected)
99103
}
100104

101105
@Preview
102106
@Composable
103107
private fun HighlightsFilterRowPreview() {
104-
HighlightsFilterRow(sportSelectionList, {})
108+
HighlightsFilterRow(sportSelectionList, SportSelection.All, {})
105109
}
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
package com.cornellappdev.score.components.highlights
2+
3+
import androidx.compose.foundation.layout.Arrangement
4+
import androidx.compose.foundation.layout.Column
5+
import androidx.compose.foundation.layout.Row
6+
import androidx.compose.foundation.layout.Spacer
7+
import androidx.compose.foundation.layout.fillMaxSize
8+
import androidx.compose.foundation.layout.fillMaxWidth
9+
import androidx.compose.foundation.layout.height
10+
import androidx.compose.foundation.layout.padding
11+
import androidx.compose.foundation.layout.width
12+
import androidx.compose.material3.Text
13+
import androidx.compose.runtime.Composable
14+
import androidx.compose.ui.Alignment
15+
import androidx.compose.ui.Modifier
16+
import androidx.compose.ui.tooling.preview.Preview
17+
import androidx.compose.ui.unit.dp
18+
import com.cornellappdev.score.components.LoadingStateBox
19+
import com.cornellappdev.score.screen.HighlightsSubScreenHeader
20+
import com.cornellappdev.score.theme.GrayStroke
21+
import com.cornellappdev.score.theme.Style.heading1
22+
import com.cornellappdev.score.theme.Style.heading2
23+
24+
@Composable
25+
fun HighlightsLoadingScreen(
26+
topHeader: String, modifier: Modifier = Modifier
27+
) {
28+
Column(
29+
modifier = modifier.fillMaxSize()
30+
) {
31+
Column(
32+
modifier = Modifier.padding(horizontal = 24.dp),
33+
horizontalAlignment = Alignment.CenterHorizontally
34+
) {
35+
Text(
36+
text = topHeader,
37+
style = heading1,
38+
color = GrayStroke,
39+
modifier = Modifier
40+
.fillMaxWidth()
41+
.align(Alignment.Start)
42+
)
43+
Spacer(modifier = Modifier.height(16.dp))
44+
LoadingStateBox(100, 40.dp)
45+
}
46+
Spacer(modifier = Modifier.height(16.dp))
47+
Row(
48+
modifier = Modifier.padding(start = 24.dp),
49+
horizontalArrangement = Arrangement.spacedBy(12.dp),
50+
) {
51+
repeat(4) {
52+
LoadingStateBox(
53+
100, 30.dp, modifier = Modifier.width(85.dp)
54+
)
55+
}
56+
}
57+
Spacer(modifier = Modifier.height(24.dp))
58+
Row(
59+
modifier = Modifier
60+
.padding(horizontal = 24.dp)
61+
.fillMaxWidth(),
62+
horizontalArrangement = Arrangement.SpaceBetween,
63+
verticalAlignment = Alignment.CenterVertically
64+
) {
65+
Text(
66+
text = "Loading Today...", style = heading2, color = GrayStroke
67+
)
68+
LoadingStateBox(
69+
100, 15.dp, modifier = Modifier.width(
70+
50.dp
71+
)
72+
)
73+
}
74+
Spacer(modifier = Modifier.height(16.dp))
75+
Row(
76+
modifier = Modifier.padding(start = 24.dp),
77+
horizontalArrangement = Arrangement.spacedBy(16.dp)
78+
) {
79+
LoadingStateBox(
80+
12, 192.dp, modifier = Modifier.width(
81+
241.dp
82+
)
83+
)
84+
LoadingStateBox(
85+
12, 192.dp, modifier = Modifier.width(
86+
241.dp
87+
)
88+
)
89+
}
90+
Spacer(modifier = Modifier.height(24.dp))
91+
Row(
92+
modifier = Modifier
93+
.padding(horizontal = 24.dp)
94+
.fillMaxWidth(),
95+
horizontalArrangement = Arrangement.SpaceBetween,
96+
verticalAlignment = Alignment.CenterVertically
97+
) {
98+
Text(
99+
text = "Loading Past 3 Days...", style = heading2, color = GrayStroke
100+
)
101+
LoadingStateBox(
102+
100, 15.dp, modifier = Modifier.width(
103+
50.dp
104+
)
105+
)
106+
}
107+
Spacer(modifier = Modifier.height(16.dp))
108+
Row(
109+
modifier = Modifier.padding(start = 24.dp),
110+
horizontalArrangement = Arrangement.spacedBy(16.dp)
111+
) {
112+
LoadingStateBox(
113+
12, 192.dp, modifier = Modifier.width(
114+
241.dp
115+
)
116+
)
117+
LoadingStateBox(
118+
12, 192.dp, modifier = Modifier.width(
119+
241.dp
120+
)
121+
)
122+
}
123+
}
124+
}
125+
126+
@Composable
127+
fun SubHighlightsLoadingScreen(
128+
header: String, modifier: Modifier = Modifier
129+
) {
130+
Column(
131+
modifier = Modifier.fillMaxWidth()
132+
) {
133+
HighlightsSubScreenHeader(
134+
header = header, navigateBack = {})
135+
Column(
136+
modifier = modifier
137+
.fillMaxWidth()
138+
.padding(start = 24.dp, end = 24.dp, top = 24.dp),
139+
horizontalAlignment = Alignment.CenterHorizontally
140+
) {
141+
LoadingStateBox(
142+
100, height = 40.dp
143+
)
144+
145+
Spacer(modifier = Modifier.height(16.dp))
146+
}
147+
Row(
148+
modifier = Modifier.padding(start = 24.dp),
149+
horizontalArrangement = Arrangement.spacedBy(12.dp),
150+
) {
151+
repeat(4) {
152+
LoadingStateBox(
153+
100, 30.dp, modifier = Modifier.width(85.dp)
154+
)
155+
}
156+
}
157+
Spacer(modifier.height(24.dp))
158+
Column(
159+
modifier = Modifier.padding(horizontal = 24.dp),
160+
verticalArrangement = Arrangement.spacedBy(16.dp)
161+
) {
162+
repeat(4) {
163+
LoadingStateBox(
164+
12, 192.dp
165+
)
166+
}
167+
}
168+
}
169+
}
170+
171+
172+
@Preview
173+
@Composable
174+
private fun HighlightsLoadingScreenPreview() =
175+
_root_ide_package_.com.cornellappdev.score.components.ScorePreview {
176+
HighlightsLoadingScreen("Loading Highlights...")
177+
}
178+
179+
@Preview
180+
@Composable
181+
private fun SubHighlightsLoadingScreenPreview() =
182+
_root_ide_package_.com.cornellappdev.score.components.ScorePreview {
183+
SubHighlightsLoadingScreen("Past 3 Days")
184+
}

0 commit comments

Comments
 (0)