Skip to content

Commit a6c076a

Browse files
committed
Refactor HighlightsViewModel
UIState no longer exposes the raw backend list. Filtered highlights are now precomputed in the ViewModel, so the UI can observe state directly without recalculating on every recomposition.
1 parent 5d1fb1d commit a6c076a

1 file changed

Lines changed: 75 additions & 48 deletions

File tree

app/src/main/java/com/cornellappdev/score/viewmodel/HighlightsViewModel.kt

Lines changed: 75 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -6,54 +6,47 @@ import com.cornellappdev.score.model.HighlightData
66
import com.cornellappdev.score.model.HighlightsRepository
77
import com.cornellappdev.score.model.Sport
88
import com.cornellappdev.score.model.SportSelection
9-
import com.cornellappdev.score.model.map
10-
import com.cornellappdev.score.util.parseIsoDateToLocalDateOrNull
119
import dagger.hilt.android.lifecycle.HiltViewModel
1210
import java.time.LocalDate
1311
import javax.inject.Inject
1412

1513
data class HighlightsUiState(
1614
val sportSelect: SportSelection,
1715
val loadedState: ApiResponse<List<HighlightData>>,
18-
val sportSelectionList: List<SportSelection>
19-
) {
20-
//TODO: refactor filters to use flows - not best practice to expose original games list to the view
21-
val filteredHighlights: List<HighlightData>
22-
get() = when (loadedState) {
23-
is ApiResponse.Success -> loadedState.data.filter { highlight ->
24-
(sportSelect is SportSelection.All ||
25-
(sportSelect is SportSelection.SportSelect && highlight.sport == sportSelect.sport))
26-
}
16+
val sportSelectionList: List<SportSelection>,
17+
val filteredHighlights: List<HighlightData>,
18+
val todayHighlights: List<HighlightData>,
19+
val pastThreeDaysHighlights: List<HighlightData>
20+
)
2721

28-
ApiResponse.Loading -> emptyList()
29-
ApiResponse.Error -> emptyList()
30-
}.sortedBy { it.date }
22+
private fun buildDerivedLists(
23+
highlights: List<HighlightData>,
24+
sportSelect: SportSelection
25+
): Triple<List<HighlightData>, List<HighlightData>, List<HighlightData>> {
3126

32-
val todayHighlights: List<HighlightData>
33-
get() = when (loadedState) {
34-
is ApiResponse.Success -> loadedState.data
27+
val today = LocalDate.now()
28+
val threeDaysAgo = today.minusDays(3)
3529

36-
ApiResponse.Loading -> emptyList()
37-
ApiResponse.Error -> emptyList()
38-
}.filter { highlight ->
39-
parseIsoDateToLocalDateOrNull(highlight.date) == LocalDate.now()
40-
}.sortedBy { highlight ->
41-
parseIsoDateToLocalDateOrNull(highlight.date)
30+
// Keep only highlights with a date and matching the sport filter
31+
val validHighlights = highlights
32+
.filter { it.date != null }
33+
.filter { highlight ->
34+
when (sportSelect) {
35+
is SportSelection.All -> true
36+
is SportSelection.SportSelect ->
37+
highlight.sport == sportSelect.sport
38+
}
4239
}
4340

44-
val pastThreeDaysHighlights: List<HighlightData>
45-
get() = when (loadedState) {
46-
is ApiResponse.Success -> loadedState.data
47-
48-
ApiResponse.Loading -> emptyList()
49-
ApiResponse.Error -> emptyList()
50-
}.filter { highlight ->
51-
val date = parseIsoDateToLocalDateOrNull(highlight.date)
52-
date != null && !date.isBefore(LocalDate.now().minusDays(3))
53-
}.sortedBy { highlight ->
54-
parseIsoDateToLocalDateOrNull(highlight.date)
55-
}
41+
val filtered = validHighlights.sortedBy { it.date }
42+
43+
val todayHighlights = validHighlights.filter { it.date == today }
44+
45+
val pastThreeDaysHighlights = validHighlights
46+
.filter { it.date!! >= threeDaysAgo } // null dates filtered out in line 32
47+
.sortedBy { it.date }
5648

49+
return Triple(filtered, todayHighlights, pastThreeDaysHighlights)
5750
}
5851

5952
@HiltViewModel
@@ -63,24 +56,48 @@ class HighlightsViewModel @Inject constructor(
6356
HighlightsUiState(
6457
sportSelect = SportSelection.All,
6558
loadedState = ApiResponse.Loading,
66-
sportSelectionList = Sport.getSportSelectionList(GenderDivision.ALL)
59+
sportSelectionList = Sport.getSportSelectionList(GenderDivision.ALL),
60+
filteredHighlights = emptyList(),
61+
todayHighlights = emptyList(),
62+
pastThreeDaysHighlights = emptyList()
6763
)
6864
) {
6965
init {
7066
highlightsRepository.fetchHighlights()
7167
asyncCollect(highlightsRepository.highlightsFlow) { response ->
7268
applyMutation {
73-
copy(
74-
loadedState = response.map { highlights ->
75-
highlights
76-
.sortedByDescending { highlight ->
77-
when (highlight) {
78-
is HighlightData.Video -> highlight.data.date
79-
is HighlightData.Article -> highlight.data.date
80-
}
81-
}
69+
when (response) {
70+
is ApiResponse.Success -> {
71+
val sorted =
72+
response.data.sortedByDescending { it.date }
73+
74+
val (filtered, today, pastThreeDays) =
75+
buildDerivedLists(sorted, sportSelect)
76+
77+
copy(
78+
loadedState = ApiResponse.Success(sorted),
79+
filteredHighlights = filtered,
80+
todayHighlights = today,
81+
pastThreeDaysHighlights = pastThreeDays
82+
)
8283
}
83-
)
84+
85+
ApiResponse.Loading ->
86+
copy(
87+
loadedState = ApiResponse.Loading,
88+
filteredHighlights = emptyList(),
89+
todayHighlights = emptyList(),
90+
pastThreeDaysHighlights = emptyList()
91+
)
92+
93+
ApiResponse.Error ->
94+
copy(
95+
loadedState = ApiResponse.Error,
96+
filteredHighlights = emptyList(),
97+
todayHighlights = emptyList(),
98+
pastThreeDaysHighlights = emptyList()
99+
)
100+
}
84101
}
85102
}
86103
}
@@ -89,14 +106,24 @@ class HighlightsViewModel @Inject constructor(
89106
applyMutation {
90107
copy(loadedState = ApiResponse.Loading)
91108
}
92-
93109
highlightsRepository.fetchHighlights()
94110
}
95111

96112
fun onSportSelected(sport: SportSelection) {
97113
applyMutation {
114+
val highlights = when (val state = loadedState) {
115+
is ApiResponse.Success -> state.data
116+
else -> emptyList()
117+
}
118+
119+
val (filtered, today, pastThreeDays) =
120+
buildDerivedLists(highlights, sport)
121+
98122
copy(
99-
sportSelect = sport
123+
sportSelect = sport,
124+
filteredHighlights = filtered,
125+
todayHighlights = today,
126+
pastThreeDaysHighlights = pastThreeDays
100127
)
101128
}
102129
}

0 commit comments

Comments
 (0)