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
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
134051d
CM FAB and basic ui structure for Bottom sheet
oliviaxjiang Apr 12, 2024
93328c7
allowed checkmarks to be selected + added navigation to screen
oliviaxjiang Apr 12, 2024
3c02335
bot sheet button color
oliviaxjiang Apr 12, 2024
7fc7e16
bottom sheet filter functionality
oliviaxjiang Apr 17, 2024
278a168
navigation passes parameter (next step: viewmodel)
oliviaxjiang Apr 17, 2024
b954171
some progress on displaying items.
oliviaxjiang Apr 19, 2024
15f896a
Update CompareMenusScreen.kt
oliviaxjiang Apr 23, 2024
8442cea
view eatery details
oliviaxjiang Apr 23, 2024
2f187b6
Changed Compare Menus Icon, added Selected Filter
Gregor-Guerrier Apr 24, 2024
387637f
no eatery menu
oliviaxjiang Apr 24, 2024
2155809
Merge branch 'main' into compare-menus
orangeorangejuice Sep 4, 2024
f8500bb
Add animations for FAB and simplify showing logic
thisjustin123 Sep 4, 2024
4a8e2d6
compare menus sticker header
orangeorangejuice Sep 22, 2024
d99096b
both row and icon button clickable
oliviaxjiang Sep 25, 2024
6541231
compare menus view model refactor
oliviaxjiang Sep 27, 2024
c308810
reformat
oliviaxjiang Sep 27, 2024
90379e0
addressing PR comments
oliviaxjiang Sep 28, 2024
201ace2
address PR comment pt 2
oliviaxjiang Sep 28, 2024
2d4740e
Update CompareMenusScreen.kt
oliviaxjiang Sep 28, 2024
a91b9bd
Update CompareMenusScreen.kt
oliviaxjiang Sep 28, 2024
878d5b6
removed unused functions in homeviewmodel
oliviaxjiang Sep 28, 2024
d5106bb
reformat code
oliviaxjiang Sep 28, 2024
4f2ad53
fix filter logic
oliviaxjiang Oct 2, 2024
9acb865
fixed favorite filter logic
oliviaxjiang Oct 2, 2024
f67c277
Refactor
zachseidner1 Oct 2, 2024
bafe771
Merge remote-tracking branch 'origin/main' into compare-menus
zachseidner1 Oct 2, 2024
ce85db8
resolved conflicts
oliviaxjiang Oct 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
package com.cornellappdev.android.eatery.ui.components.comparemenus

import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Check
import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.outlined.Schedule
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.ViewModel
import com.cornellappdev.android.eatery.data.models.Eatery
import com.cornellappdev.android.eatery.ui.components.general.CompareFilterRow
import com.cornellappdev.android.eatery.ui.components.general.Filter
import com.cornellappdev.android.eatery.ui.components.general.FilterRow
import com.cornellappdev.android.eatery.ui.components.home.MainLoadingItem
import com.cornellappdev.android.eatery.ui.theme.EateryBlue
import com.cornellappdev.android.eatery.ui.theme.EateryBlueTypography
import com.cornellappdev.android.eatery.ui.theme.GrayFive
import com.cornellappdev.android.eatery.ui.theme.GrayTwo
import com.cornellappdev.android.eatery.ui.theme.GrayZero
import com.cornellappdev.android.eatery.ui.viewmodels.CompareMenusBotViewModel
import com.cornellappdev.android.eatery.ui.viewmodels.CompareMenusViewModel
import com.cornellappdev.android.eatery.ui.viewmodels.HomeViewModel
import com.cornellappdev.android.eatery.ui.viewmodels.state.CompareMenusUIState
import com.cornellappdev.android.eatery.ui.viewmodels.state.EateryApiResponse
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

@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.

compareMenusBotViewModel: CompareMenusBotViewModel = hiltViewModel()
zachseidner1 marked this conversation as resolved.
Show resolved Hide resolved
) {
val compareMenusUIState by compareMenusBotViewModel.compareMenusUiState.collectAsState()
val filters = compareMenusUIState.filters
val selectedEateries = compareMenusUIState.selected
val eateries = compareMenusUIState.eateries

Column(
modifier = Modifier
.fillMaxWidth()
.padding(top = 14.dp)
.padding(16.dp),
horizontalAlignment = Alignment.Start
) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(
text = "Compare Menus", style = EateryBlueTypography.h4,
color = Color.Black
)
IconButton(
onClick = {
compareMenusBotViewModel.resetSelected()
onDismiss()
},
modifier = Modifier
.size(40.dp)
.background(color = GrayZero, shape = CircleShape)
) {
Icon(
Icons.Default.Close,
contentDescription = Icons.Default.Close.name,
tint = Color.Black
)
}
}

CompareFilterRow(
currentFiltersSelected = filters,
onPaymentMethodsClicked = {},
onFilterClicked = { filter ->
if (filters.contains(filter)) {
compareMenusBotViewModel.removeFilterCM(filter)
} else {
compareMenusBotViewModel.addFilterCM(filter)
}
})

Spacer(modifier = Modifier.height(12.dp))

Box(
modifier = Modifier
.background(Color.White)
.fillMaxHeight(0.4f)
.fillMaxWidth()
) {
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!

modifier = Modifier.fillMaxWidth().clickable {
if (selectedEateries.contains(eatery)) {
compareMenusBotViewModel.removeSelected(eatery)
} else {
compareMenusBotViewModel.addSelected(eatery)
}
},
verticalAlignment = Alignment.CenterVertically,

) {
IconButton(
onClick = {
if (selectedEateries.contains(eatery)) {
compareMenusBotViewModel.removeSelected(eatery)
} else {
compareMenusBotViewModel.addSelected(eatery)
}
},
modifier = Modifier.align(Alignment.CenterVertically)
) {
if (selectedEateries.contains(eatery)) {
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.size(26.dp)
.background(Color.Black, CircleShape)
) {
Icon(
imageVector = Icons.Default.Check,
contentDescription = "Selected",
tint = Color.White,
modifier = Modifier.size(24.dp)
)
}
} else {
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.size(26.dp)
.background(Color.White, CircleShape)
.border(2.dp, Color.Black, CircleShape)
) {
}
}
}
eatery.name?.let {
Text(
text = it, style = EateryBlueTypography.body1,
color = Color.Black
)
}
}


}
}
}

Spacer(modifier = Modifier.height(12.dp))
val coroutineScope = rememberCoroutineScope()
Button(
onClick = {
if (selectedEateries.size < 2){

}
else{
coroutineScope.launch {
delay(100)
onCompareMenusClick(compareMenusUIState.selected)
}
}
},
modifier = Modifier
.fillMaxWidth()
.height(48.dp)
.align(Alignment.CenterHorizontally),
shape = RoundedCornerShape(100),
colors = ButtonDefaults.buttonColors(
backgroundColor = if (selectedEateries.size < 2) GrayTwo else EateryBlue,
contentColor = if (selectedEateries.size < 2) GrayZero else Color.White
)
) {
Text(
text = if (selectedEateries.size < 2) "Select at least ${2 - selectedEateries.size} more"
else "Compare ${selectedEateries.size} now",
style = EateryBlueTypography.h5,
color = Color.White
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.cornellappdev.android.eatery.ui.components.comparemenus

import androidx.compose.foundation.layout.padding
import androidx.compose.material.FloatingActionButton
import androidx.compose.material.Icon
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import com.cornellappdev.android.eatery.R
import com.cornellappdev.android.eatery.ui.theme.EateryBlue

@Composable
fun CompareMenusFAB(
modifier: Modifier = Modifier,
onClick: () -> Unit
) {
FloatingActionButton(
onClick = { onClick() },
modifier = modifier
.padding(16.dp),
backgroundColor = EateryBlue
) {
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

tint = Color.White
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,9 @@ fun EateryDetailsStickyHeader(
filterText: String,
fullMenuList: MutableList<String>,
listState: LazyListState,
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 rowState = rememberLazyListState()
val rowCoroutine = rememberCoroutineScope()
Expand All @@ -71,7 +72,8 @@ fun EateryDetailsStickyHeader(
category,
listState,
nextEvent,
fullMenuList
fullMenuList,
startIndex
)
}
val selectedIndex: Int =
Expand All @@ -90,52 +92,7 @@ fun EateryDetailsStickyHeader(
modifier = Modifier
.fillMaxWidth()
.background(Color.White)
.padding(top = 48.dp, bottom = 12.dp)
) {
Box(
modifier = Modifier
.fillMaxWidth()
.height(40.dp)
) {
Text(
modifier = Modifier
.height(26.dp)
.widthIn(0.dp, 280.dp)
.align(Alignment.Center),
textAlign = TextAlign.Center,
text = eatery.name ?: "Loading...",
maxLines = 1,
overflow = TextOverflow.Ellipsis,
color = Color.Black,
style = TextStyle(
fontWeight = FontWeight.SemiBold,
fontSize = 20.sp
)
)

Button(
onClick = { eateryDetailViewModel.toggleFavorite() },
modifier = Modifier
.align(Alignment.CenterEnd)
.padding(end = 16.dp)
.size(40.dp),
contentPadding = PaddingValues(6.dp),
shape = CircleShape,
colors = ButtonDefaults.buttonColors(
backgroundColor = Color.White,
),
elevation = ButtonDefaults.elevation(
defaultElevation = 0.dp,
pressedElevation = 0.dp
)
) {
Icon(
imageVector = if (eateryDetailViewModel.isFavorite) Icons.Filled.Star else Icons.Outlined.StarOutline,
tint = if (eateryDetailViewModel.isFavorite) Yellow else GrayFive,
contentDescription = null
)
}
}

Spacer(modifier = Modifier.height(6.dp))

Expand Down Expand Up @@ -167,7 +124,8 @@ fun EateryDetailsStickyHeader(
category,
listState,
nextEvent,
fullMenuList
fullMenuList,
startIndex
)
CategoryItem(
category.category ?: "Category",
Expand All @@ -192,6 +150,7 @@ fun EateryDetailsStickyHeader(
}
}
}
Spacer(modifier = Modifier.height(6.dp))
}

Divider(
Expand Down Expand Up @@ -245,12 +204,13 @@ fun highlightCategory(
category: MenuCategory,
listState: LazyListState,
nextEvent: Event?,
fullMenuList: MutableList<String>
fullMenuList: MutableList<String>,
startIndex: Int
): Boolean {
val firstVisibleState = remember { derivedStateOf { listState.firstVisibleItemIndex } }
// Note: - 5 here assumes that there are 5 UI elements above the menu, which is true currently.
// If that changes, this must be tweaked.
val firstMenuItemIndex = firstVisibleState.value - 5
val firstMenuItemIndex = firstVisibleState.value - startIndex

if (firstMenuItemIndex >= 0 && firstMenuItemIndex < fullMenuList.size) {
val item = fullMenuList[firstMenuItemIndex]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ enum class Filter(val text: String) {
FAVORITES("Favorites"),
BRB("BRBs"),
CASH("Cash or credit"),
SWIPES("Meal swipes");
SWIPES("Meal swipes"),
SELECTED("Selected");

companion object {
val PAYMENT_METHODS = setOf(BRB, CASH, SWIPES)
Expand Down
Loading