Skip to content

Commit 92ca9c0

Browse files
committed
feat: add hard-coded images for each library and take user directly to route when clicked instead of empty detail screen
1 parent 5e4023c commit 92ca9c0

16 files changed

Lines changed: 130 additions & 20 deletions

app/src/main/java/com/cornellappdev/transit/ui/components/home/EcosystemBottomSheetContent.kt

Lines changed: 42 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import com.cornellappdev.transit.ui.theme.robotoFamily
4343
import com.cornellappdev.transit.ui.viewmodels.EcosystemFavoritesUiState
4444
import com.cornellappdev.transit.ui.viewmodels.FavoritesFilterSheetState
4545
import com.cornellappdev.transit.ui.viewmodels.FilterState
46+
import com.cornellappdev.transit.ui.viewmodels.LibraryCardUiState
4647
import com.cornellappdev.transit.util.TimeUtils.isOpenAnnotatedStringFromOperatingHours
4748
import com.cornellappdev.transit.util.ecosystem.capacityPercentAnnotatedString
4849
import com.cornellappdev.transit.ui.viewmodels.PrinterCardUiState
@@ -65,6 +66,7 @@ fun EcosystemBottomSheetContent(
6566
activeFilter: FilterState,
6667
onFilterClick: (FilterState) -> Unit,
6768
staticPlaces: StaticPlaces,
69+
libraryCardsApiResponse: ApiResponse<List<LibraryCardUiState>>,
6870
favorites: Set<Place>,
6971
favoritesUiState: EcosystemFavoritesUiState,
7072
modifier: Modifier = Modifier,
@@ -119,6 +121,7 @@ fun EcosystemBottomSheetContent(
119121
BottomSheetFilteredContent(
120122
currentFilter = activeFilter,
121123
staticPlaces = staticPlaces,
124+
libraryCardsApiResponse = libraryCardsApiResponse,
122125
favorites = favorites,
123126
favoritesUiState = favoritesUiState,
124127
navigateToPlace = navigateToPlace,
@@ -153,6 +156,7 @@ fun EcosystemBottomSheetContent(
153156
private fun BottomSheetFilteredContent(
154157
currentFilter: FilterState,
155158
staticPlaces: StaticPlaces,
159+
libraryCardsApiResponse: ApiResponse<List<LibraryCardUiState>>,
156160
favorites: Set<Place>,
157161
favoritesUiState: EcosystemFavoritesUiState,
158162
navigateToPlace: (Place) -> Unit,
@@ -200,7 +204,7 @@ private fun BottomSheetFilteredContent(
200204
favorites = favorites,
201205
filteredFavorites = favoritesUiState.filteredSortedFavorites,
202206
eateryByPlace = favoritesUiState.eateryByPlace,
203-
libraryByPlace = favoritesUiState.libraryByPlace,
207+
libraryCardByPlace = favoritesUiState.libraryCardByPlace,
204208
gymByPlace = favoritesUiState.gymByPlace,
205209
printerByPlace = favoritesUiState.printerByPlace,
206210
navigateToPlace = navigateToPlace,
@@ -248,7 +252,7 @@ private fun BottomSheetFilteredContent(
248252

249253
FilterState.LIBRARIES -> {
250254
libraryList(
251-
staticPlaces,
255+
libraryCardsApiResponse,
252256
navigateToPlace,
253257
onDetailsClick,
254258
favorites,
@@ -269,7 +273,7 @@ private fun LazyListScope.favoriteList(
269273
favorites: Set<Place>,
270274
filteredFavorites: List<Place>,
271275
eateryByPlace: Map<Place, Eatery>,
272-
libraryByPlace: Map<Place, Library>,
276+
libraryCardByPlace: Map<Place, LibraryCardUiState>,
273277
gymByPlace: Map<Place, UpliftGym>,
274278
printerByPlace: Map<Place, PrinterCardUiState>,
275279
navigateToPlace: (Place) -> Unit,
@@ -319,18 +323,22 @@ private fun LazyListScope.favoriteList(
319323
}
320324

321325
PlaceType.LIBRARY -> {
322-
val matchingLibrary = libraryByPlace[place]
323-
if (matchingLibrary != null) {
326+
val matchingLibraryCard = libraryCardByPlace[place]
327+
if (matchingLibraryCard != null) {
328+
val matchingLibrary = matchingLibraryCard.library
324329
RoundedImagePlaceCard(
325330
title = matchingLibrary.location,
326331
subtitle = matchingLibrary.address + distanceStringToPlace(
327332
matchingLibrary.latitude,
328333
matchingLibrary.longitude
329334
),
330335
isFavorite = true,
331-
onFavoriteClick = { onFavoriteStarClick(place) }
336+
onFavoriteClick = { onFavoriteStarClick(place) },
337+
placeholderRes = matchingLibraryCard.placeholderRes
332338
) {
333-
onDetailsClick(matchingLibrary)
339+
// Use detailed content sheet when backend is updated
340+
// onDetailsClick(matchingLibrary)
341+
navigateToPlace(matchingLibrary.toPlace())
334342
}
335343
} else {
336344
StandardCard(
@@ -564,32 +572,35 @@ private fun LazyListScope.eateryList(
564572
* LazyList scoped enumeration of libraries for bottom sheet
565573
*/
566574
private fun LazyListScope.libraryList(
567-
staticPlaces: StaticPlaces,
575+
libraryCardsApiResponse: ApiResponse<List<LibraryCardUiState>>,
568576
navigateToPlace: (Place) -> Unit,
569577
navigateToDetails: (DetailedEcosystemPlace) -> Unit,
570578
favorites: Set<Place>,
571579
onFavoriteStarClick: (Place) -> Unit,
572580
distanceStringToPlace: (Double?, Double?) -> String,
573581
) {
574-
when (staticPlaces.libraries) {
582+
when (libraryCardsApiResponse) {
575583
is ApiResponse.Error -> {
576584
}
577585

578586
is ApiResponse.Pending -> {
579587
}
580588

581589
is ApiResponse.Success -> {
582-
items(staticPlaces.libraries.data) {
590+
items(libraryCardsApiResponse.data) {
591+
val library = it.library
583592
RoundedImagePlaceCard(
584-
placeholderRes = R.drawable.olin_library,
585-
title = it.location,
586-
subtitle = it.address + distanceStringToPlace(it.latitude, it.longitude),
587-
isFavorite = it.toPlace() in favorites,
593+
placeholderRes = it.placeholderRes,
594+
title = library.location,
595+
subtitle = library.address + distanceStringToPlace(library.latitude, library.longitude),
596+
isFavorite = library.toPlace() in favorites,
588597
onFavoriteClick = {
589-
onFavoriteStarClick(it.toPlace())
598+
onFavoriteStarClick(library.toPlace())
590599
}
591600
) {
592-
navigateToDetails(it)
601+
// Use detailed content sheet when backend is updated
602+
// navigateToDetails(library)
603+
navigateToPlace(library.toPlace())
593604
}
594605
}
595606
}
@@ -635,6 +646,7 @@ private fun PreviewEcosystemBottomSheet() {
635646
ApiResponse.Pending,
636647
ApiResponse.Pending
637648
),
649+
libraryCardsApiResponse = ApiResponse.Pending,
638650
favorites = emptySet(),
639651
favoritesUiState = EcosystemFavoritesUiState(),
640652
modifier = Modifier,
@@ -716,6 +728,14 @@ private fun PreviewBottomSheetFilteredContentFavorites() {
716728
eateries = ApiResponse.Success(listOf(mockEatery)),
717729
gyms = ApiResponse.Success(listOf(mockGym))
718730
),
731+
libraryCardsApiResponse = ApiResponse.Success(
732+
listOf(
733+
LibraryCardUiState(
734+
library = mockLibrary,
735+
placeholderRes = R.drawable.olin_library
736+
)
737+
)
738+
),
719739
favorites = setOf(
720740
Place(
721741
latitude = 42.4488,
@@ -792,7 +812,12 @@ private fun PreviewBottomSheetFilteredContentFavorites() {
792812
)
793813
),
794814
eateryByPlace = listOf(mockEatery).associateBy { it.toPlace() },
795-
libraryByPlace = listOf(mockLibrary).associateBy { it.toPlace() },
815+
libraryCardByPlace = mapOf(
816+
mockLibrary.toPlace() to LibraryCardUiState(
817+
library = mockLibrary,
818+
placeholderRes = R.drawable.olin_library
819+
)
820+
),
796821
gymByPlace = listOf(mockGym).associateBy { it.toPlace() },
797822
printerByPlace = mapOf(
798823
mockPrinter.toPlace() to PrinterCardUiState(

app/src/main/java/com/cornellappdev/transit/ui/screens/HomeScreen.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ fun HomeScreen(
184184
val filterStateValue = homeViewModel.filterState.collectAsStateWithLifecycle().value
185185

186186
val staticPlaces = homeViewModel.staticPlacesFlow.collectAsStateWithLifecycle().value
187+
val libraryCardsApiResponse = homeViewModel.libraryCardsFlow.collectAsStateWithLifecycle().value
187188
val ecosystemFavoritesUiState =
188189
homeViewModel.ecosystemFavoritesUiState.collectAsStateWithLifecycle().value
189190

@@ -336,6 +337,7 @@ fun HomeScreen(
336337
onFilterClick = homeViewModel::setCategoryFilter,
337338
modifier = Modifier.onTapDisableSearch(),
338339
staticPlaces = staticPlaces,
340+
libraryCardsApiResponse = libraryCardsApiResponse,
339341
favorites = favorites,
340342
favoritesUiState = ecosystemFavoritesUiState,
341343
navigateToPlace = {

app/src/main/java/com/cornellappdev/transit/ui/viewmodels/HomeViewModel.kt

Lines changed: 86 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package com.cornellappdev.transit.ui.viewmodels
22

33
import android.content.Context
4+
import androidx.annotation.DrawableRes
45
import androidx.lifecycle.ViewModel
56
import androidx.lifecycle.viewModelScope
7+
import com.cornellappdev.transit.R
68
import com.cornellappdev.transit.models.LocationRepository
79
import com.cornellappdev.transit.models.Place
810
import com.cornellappdev.transit.models.PlaceType
@@ -49,6 +51,25 @@ class HomeViewModel @Inject constructor(
4951
private val selectedRouteRepository: SelectedRouteRepository
5052
) : ViewModel() {
5153

54+
val libraryCardsFlow: StateFlow<ApiResponse<List<LibraryCardUiState>>> =
55+
routeRepository.libraryFlow.map { response ->
56+
when (response) {
57+
is ApiResponse.Success -> {
58+
ApiResponse.Success(
59+
response.data
60+
.filterNot { it.isExcludedLibrary() }
61+
.map { it.toLibraryCardUiState() }
62+
)
63+
}
64+
is ApiResponse.Pending -> ApiResponse.Pending
65+
is ApiResponse.Error -> ApiResponse.Error
66+
}
67+
}.stateIn(
68+
scope = viewModelScope,
69+
started = SharingStarted.Eagerly,
70+
initialValue = ApiResponse.Pending
71+
)
72+
5273
/**
5374
* The current query in the add favorites search bar, as a StateFlow
5475
*/
@@ -97,7 +118,7 @@ class HomeViewModel @Inject constructor(
97118
) { printers, libraries, eateries, gyms ->
98119
StaticPlaces(
99120
printers,
100-
libraries,
121+
libraries.withExcludedLibrariesRemoved(),
101122
eateries,
102123
gyms
103124
)
@@ -146,6 +167,7 @@ class HomeViewModel @Inject constructor(
146167

147168
val filteredSortedFavorites = favorites.asSequence()
148169
.filter { allowedTypes.isEmpty() || it.type in allowedTypes }
170+
.filterNot { it.isExcludedLibraryPlace() }
149171
.sortedWith(compareBy<Place>({ it.type.ordinal }, { it.name }))
150172
.toList()
151173

@@ -157,7 +179,9 @@ class HomeViewModel @Inject constructor(
157179
EcosystemFavoritesUiState(
158180
filteredSortedFavorites = filteredSortedFavorites,
159181
eateryByPlace = eateries.associateBy { it.toPlace() },
160-
libraryByPlace = libraries.associateBy { it.toPlace() },
182+
libraryCardByPlace = libraries
183+
.map { it.toLibraryCardUiState() }
184+
.associateBy { it.library.toPlace() },
161185
gymByPlace = gyms.associateBy { it.toPlace() },
162186
printerByPlace = printers.associate { printer ->
163187
val place = printer.toPlace()
@@ -402,11 +426,19 @@ class HomeViewModel @Inject constructor(
402426
data class EcosystemFavoritesUiState(
403427
val filteredSortedFavorites: List<Place> = emptyList(),
404428
val eateryByPlace: Map<Place, Eatery> = emptyMap(),
405-
val libraryByPlace: Map<Place, Library> = emptyMap(),
429+
val libraryCardByPlace: Map<Place, LibraryCardUiState> = emptyMap(),
406430
val gymByPlace: Map<Place, UpliftGym> = emptyMap(),
407431
val printerByPlace: Map<Place, PrinterCardUiState> = emptyMap()
408432
)
409433

434+
/**
435+
* UI-ready library fields so composables receive configured fallback/override images.
436+
*/
437+
data class LibraryCardUiState(
438+
val library: Library,
439+
@DrawableRes val placeholderRes: Int
440+
)
441+
410442
/**
411443
* UI-ready printer fields so composables don't parse backend strings.
412444
*/
@@ -431,6 +463,57 @@ private fun Printer.toPrinterCardUiState(): PrinterCardUiState {
431463
)
432464
}
433465

466+
private val libraryImageOverridesByLocation: Map<String, Int> = mapOf(
467+
// Temporary placeholders: each location is explicitly configurable for future per-library assets.
468+
"africana studies and research center" to R.drawable.library_img_africana_studies,
469+
"carpenter hall" to R.drawable.library_img_carpenter_hall,
470+
"clark hall" to R.drawable.library_img_clark_hall,
471+
"comstock hall" to R.drawable.library_img_comstock_hall,
472+
"imogene powers johnson center for birds and biodiversity" to R.drawable.olin_library,
473+
"ives hall" to R.drawable.library_img_ives_hall,
474+
"jordan hall" to R.drawable.olin_library,
475+
"lincoln hall" to R.drawable.library_img_lincoln_hall,
476+
"malott hall" to R.drawable.library_img_malott_hall,
477+
"mann library" to R.drawable.library_img_mann_library,
478+
"myron taylor hall" to R.drawable.library_img_myron_taylor_hall,
479+
"myron taylor jane foster library addition" to R.drawable.olin_library,
480+
"olin library" to R.drawable.olin_library,
481+
"rand hall" to R.drawable.library_img_rand_hall,
482+
"sage hall" to R.drawable.library_img_sage_hall,
483+
"statler hall" to R.drawable.library_img_statler_hall,
484+
"vet education center" to R.drawable.library_img_vet_center
485+
)
486+
487+
private val excludedLibraryLocations: Set<String> = setOf(
488+
"imogene powers johnson center for birds and biodiversity",
489+
"myron taylor jane foster library addition",
490+
"jordan hall"
491+
)
492+
493+
private fun ApiResponse<List<Library>>.withExcludedLibrariesRemoved(): ApiResponse<List<Library>> {
494+
return when (this) {
495+
is ApiResponse.Success -> ApiResponse.Success(data.filterNot { it.isExcludedLibrary() })
496+
is ApiResponse.Pending -> ApiResponse.Pending
497+
is ApiResponse.Error -> ApiResponse.Error
498+
}
499+
}
500+
501+
private fun Library.isExcludedLibrary(): Boolean {
502+
return location.trim().lowercase() in excludedLibraryLocations
503+
}
504+
505+
private fun Place.isExcludedLibraryPlace(): Boolean {
506+
return type == PlaceType.LIBRARY && name.trim().lowercase() in excludedLibraryLocations
507+
}
508+
509+
private fun Library.toLibraryCardUiState(): LibraryCardUiState {
510+
val normalizedLocation = location.trim().lowercase()
511+
return LibraryCardUiState(
512+
library = this,
513+
placeholderRes = libraryImageOverridesByLocation[normalizedLocation] ?: R.drawable.olin_library
514+
)
515+
}
516+
434517
private fun Set<FavoritesFilterSheetState>.toAllowedPlaceTypes(): Set<PlaceType> = buildSet {
435518
if (FavoritesFilterSheetState.EATERIES in this@toAllowedPlaceTypes) add(PlaceType.EATERY)
436519
if (FavoritesFilterSheetState.LIBRARIES in this@toAllowedPlaceTypes) add(PlaceType.LIBRARY)
222 KB
Loading
1.65 MB
Loading
855 KB
Loading
553 KB
Loading
236 KB
Loading
1.8 MB
Loading
256 KB
Loading

0 commit comments

Comments
 (0)