Skip to content
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

Merged
merged 27 commits into from
Oct 3, 2024
Merged

Compare menus #148

merged 27 commits into from
Oct 3, 2024

Conversation

oliviaxjiang
Copy link
Contributor

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 LaunchedEffect

3. 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 (?))

Copy link
Contributor

@zachseidner1 zachseidner1 left a 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,
Copy link
Contributor

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(
Copy link
Contributor

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.

Copy link
Contributor

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.

Copy link
Contributor

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.",
Copy link
Contributor

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(
Copy link
Contributor

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)
Copy link
Contributor

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()
Copy link
Contributor

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
Copy link
Contributor

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(
Copy link
Contributor

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) }

Copy link
Contributor

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!

Copy link
Contributor

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?

Copy link
Contributor

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?

Copy link
Contributor

@thisjustin123 thisjustin123 left a 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.

) {
LazyColumn {
items(eateries) { eatery ->
Row(
Copy link
Contributor

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(
Copy link
Contributor

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!

Comment on lines 64 to 65
eateryDetailViewModel: EateryDetailViewModel = hiltViewModel(),
onItemClick: (Int) -> Unit
startIndex : Int,
onItemClick: (Int) -> Unit,
Copy link
Contributor

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){
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I smell unformatted file >:)

Comment on lines 57 to 58
val showBottomBar = rememberSaveable { mutableStateOf(false)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Strange formatting!

Comment on lines 431 to 446
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}")
}
)
}
}
Copy link
Contributor

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!

Copy link
Contributor

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.

Copy link
Contributor

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
Copy link
Contributor

@zachseidner1 zachseidner1 left a 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
@oliviaxjiang oliviaxjiang merged commit 78be1e7 into main Oct 3, 2024
@thisjustin123 thisjustin123 deleted the compare-menus branch October 23, 2024 16:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants