-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Compare menus #148
Compare menus #148
Conversation
in compare menus bot sheet
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a great first draft! I like your decision to give the compare menus bottom sheet a ViewModel
and injecting it via hiltViewModel()
. After seeing all the filtering logic it definitely makes sense. There are a bit of comments that you need to work through, anything, so much so that anything I labeled with "nit" don't feel pressure to fix. But I really appreciate the work you've put into implementing this and I hope you've learned more about Android architecture!
@Composable | ||
fun CompareMenusBotSheet( | ||
onDismiss: () -> Unit, | ||
onCompareMenusClick: (selectedEateries : List<Eatery>) -> Unit, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since you map this to a list of IDs anyway, this should be (selectedEateryIds: List<Int>) -> Unit
.
) { | ||
LazyColumn { | ||
items(eateries) { eatery -> | ||
Row( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you abstract this component into a private composable like EateryTextRow
, that takes an eatery name as a parameter? I think it could make this file a bit more readable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ya good point! There's a lot of indentation here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's generally good to take out the header, content, and bottom portions into separate composables for readability.
Veronica discovered this feature where you just highlight a bunch of your function and hit Extract
that pops up and it does this all for you. I don't know how accurate/good it is though, but perhaps try it out!
) { | ||
Icon( | ||
painter = painterResource(id = R.drawable.ic_compare_menus), | ||
"Floating action button.", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: could you label this with "Compare menus" for accessibility
@@ -110,6 +110,100 @@ fun FilterRow( | |||
} | |||
} | |||
|
|||
@Composable | |||
fun CompareFilterRow( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: all top level Composable functions should have previews associated with them
|
||
@OptIn(ExperimentalPagerApi::class, ExperimentalFoundationApi::class) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: remove ExperimentalPagerApi::class since it is unused
filters = currentState.filters + listOf(filter) | ||
) | ||
} | ||
updateFilteredEateries() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We shouldn't force the implementer to remember to call this updateFilteredEateries
method. This is what flows are for! We can combine a favorites flow, filters flow, and eatery flow and allow this update to happen automatically whenever the filters flow changes. This isn't too big of a deal though, and I know I've already left a lot of comments, so you don't have to address this. It probably would be fun to write though.
} | ||
|
||
if (filters.contains(Filter.FAVORITES)) { | ||
passesFilter = favorites[eatery.id] == true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it fails the under 10 filter but passes the favorites filter, then wouldn't this code make it so it still shows?
} | ||
} | ||
|
||
private fun passesFilter( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: I think a more clean implementation would be to create a map of filters
to selector functions, such that each Filter
maps to some (Eatery) -> Boolean
expression. Then this function would just return filters.all { it.mapToFilter()(eatery) }
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice job with this overall!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are we changing this file? All the state for CompareMenusBottomSheet
should be stored in the ViewModel
that corresponds to it right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh yeah good point... what are all these functions for?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll defer the approval of this PR to zach since his comments are incredibly comprehensive. But I just left some tiny additional comments.
Thanks for the review Zach. U da man.
...ain/java/com/cornellappdev/android/eatery/ui/components/comparemenus/CompareMenusBotSheet.kt
Show resolved
Hide resolved
) { | ||
LazyColumn { | ||
items(eateries) { eatery -> | ||
Row( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ya good point! There's a lot of indentation here.
) { | ||
LazyColumn { | ||
items(eateries) { eatery -> | ||
Row( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's generally good to take out the header, content, and bottom portions into separate composables for readability.
Veronica discovered this feature where you just highlight a bunch of your function and hit Extract
that pops up and it does this all for you. I don't know how accurate/good it is though, but perhaps try it out!
eateryDetailViewModel: EateryDetailViewModel = hiltViewModel(), | ||
onItemClick: (Int) -> Unit | ||
startIndex : Int, | ||
onItemClick: (Int) -> Unit, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice, love the removal of viewmodel.
val pagerState = androidx.compose.foundation.pager.rememberPagerState() | ||
androidx.compose.foundation.pager.HorizontalPager(pageCount = 2, state = pagerState, modifier = Modifier.offset(x = -8.dp)){ | ||
Column{ | ||
when(it){ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I smell unformatted file >:)
val showBottomBar = rememberSaveable { mutableStateOf(false) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Strange formatting!
composable( | ||
route = "comparemenus/{eateryIds}", | ||
arguments = listOf(navArgument("eateryIds") { type = NavType.StringType }), | ||
enterTransition = { fadeIn(animationSpec = tween(durationMillis = 500)) }, | ||
exitTransition = { fadeOut(animationSpec = tween(durationMillis = 500)) } | ||
) { backStackEntry -> | ||
backStackEntry.arguments?.getString("eateryIds")?.split(",")?.map { it.toInt() }?.let { eateryIds -> | ||
CompareMenusScreen( | ||
eateryIds = eateryIds, | ||
onEateryClick = { | ||
FirstTimeShown.firstTimeShown = false | ||
navController.navigate("${Routes.EATERY_DETAIL.route}/${it.id}") | ||
} | ||
) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lovely stuff, this passing of IDs is exactly what we need!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh god yeah let's split this up.
app/src/main/java/com/cornellappdev/android/eatery/ui/viewmodels/CompareMenusBotViewModel.kt
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh yeah good point... what are all these functions for?
- onCompareMenusClick now requires List<Int> instead of List<Eatery> so navigation doesn't take care of the id mapping - extracted lazy list in CM bottom sheet
- added compare menus key word to CM FAB content description - only one flow (UiState) in compare menus bot sheet view model - private composable in compare menus screen
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
W
# Conflicts: # app/src/main/java/com/cornellappdev/android/eatery/ui/screens/EateryDetailScreen.kt # app/src/main/java/com/cornellappdev/android/eatery/ui/screens/HomeScreen.kt
bafe771
to
f67c277
Compare
Problems Addressed
1. Issue #142: Scrolling Header
✅ Resolved by refactoring the EateryDetailsStickerHeader and using it in CompareMenusScreen
2. Issue #141: Sheet Stays Open
✅ Fixed by adding an additional close line to
OnCompareMenusClick
. Did not used NavController or LaunchedEffect3. Issue #140: Formatting Stuff
🟡 Fixed except middle format issue Figma design is rectangular borders, so idk how to fix
4. Issue #138: Row Clickable
✅ Fixed this issue per the outlined requirements. The app behavior should now match the expected outcome described in the issue.
5. Issue #139 : eatery name bottom padding
✅ Fixed added padding according to figma design
6. Issue #137: Not Done
🚫 Not Addressed: IDK what filter cuts off means.
View Model Logic Description
CompareMenusBotSheet needs to manage its own states (adding/removing selected eateries/filters) so it gets it's own viewModel (CompareMenusBotViewModel). CompareMenusScreen also needs state management, so it also gets a view model (CompareMenusViewModel). No specific viewmodel logic resides in HomeViewModel or EateryDetailsViewModel as they are all delegated to the two new view models.
Potential places for change (Would love advice here!)
List called eateryIds currently gets sent to CompareMenusScreen and CompareMenusScreen has to call a function to pass that information into the viewmodel, may want to used sharedStateHandle and give it directly to CompareMenusViewModel? (I tried looking up on StackOverFlow on how to share states between two screens that is connected via NavController and someone said that the best practice would be sharedViewModel (?))