From c07e074884cbe7940d32fb97d89c82025a472d29 Mon Sep 17 00:00:00 2001 From: Nandini Date: Mon, 15 Jul 2024 22:52:54 -0400 Subject: [PATCH 01/21] Implementing UI for purchase screen + placeholder for benefits page --- .../card/clarity/presentation/BenefitsPage.kt | 46 +++++++++++ app/src/main/res/drawable/entertainment.xml | 15 ++++ app/src/main/res/drawable/furniture.xml | 78 +++++++++++++++++++ app/src/main/res/drawable/gas.xml | 27 +++++++ app/src/main/res/drawable/groceries.xml | 24 ++++++ .../main/res/drawable/home_improvement.xml | 9 +++ app/src/main/res/drawable/hotel.xml | 24 ++++++ app/src/main/res/drawable/others.xml | 27 +++++++ app/src/main/res/drawable/pharmacy.xml | 24 ++++++ app/src/main/res/drawable/restaurants.xml | 48 ++++++++++++ app/src/main/res/drawable/travel.xml | 33 ++++++++ 11 files changed, 355 insertions(+) create mode 100644 app/src/main/java/edu/card/clarity/presentation/BenefitsPage.kt create mode 100644 app/src/main/res/drawable/entertainment.xml create mode 100644 app/src/main/res/drawable/furniture.xml create mode 100644 app/src/main/res/drawable/gas.xml create mode 100644 app/src/main/res/drawable/groceries.xml create mode 100644 app/src/main/res/drawable/home_improvement.xml create mode 100644 app/src/main/res/drawable/hotel.xml create mode 100644 app/src/main/res/drawable/others.xml create mode 100644 app/src/main/res/drawable/pharmacy.xml create mode 100644 app/src/main/res/drawable/restaurants.xml create mode 100644 app/src/main/res/drawable/travel.xml diff --git a/app/src/main/java/edu/card/clarity/presentation/BenefitsPage.kt b/app/src/main/java/edu/card/clarity/presentation/BenefitsPage.kt new file mode 100644 index 0000000..f9a23f7 --- /dev/null +++ b/app/src/main/java/edu/card/clarity/presentation/BenefitsPage.kt @@ -0,0 +1,46 @@ +package edu.card.clarity.presentation + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.navigation.NavController +import androidx.navigation.compose.rememberNavController + +@Composable +fun BenefitsScreen(navController: NavController, category: String) { + Column( + modifier = Modifier + .fillMaxSize() + .background(Color.White) + .padding(horizontal = 32.dp, vertical = 40.dp), + ) { + Text( + text = "Benefits for $category", + fontWeight = FontWeight.Bold, + fontSize = 22.sp, + color = Color.Black + ) + + Spacer(modifier = Modifier.height(24.dp)) + Text( + text = "List of benefits based on saved cards for $category", + fontWeight = FontWeight.Normal, + fontSize = 18.sp, + color = Color.Black + ) + } +} + +@Composable +@Preview +fun BenefitsScreenPreview() { + val navController = rememberNavController() + BenefitsScreen(navController, category = "Pharmacy") +} diff --git a/app/src/main/res/drawable/entertainment.xml b/app/src/main/res/drawable/entertainment.xml new file mode 100644 index 0000000..ba7b2c8 --- /dev/null +++ b/app/src/main/res/drawable/entertainment.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/app/src/main/res/drawable/furniture.xml b/app/src/main/res/drawable/furniture.xml new file mode 100644 index 0000000..f0e27d6 --- /dev/null +++ b/app/src/main/res/drawable/furniture.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/gas.xml b/app/src/main/res/drawable/gas.xml new file mode 100644 index 0000000..bd0b3a1 --- /dev/null +++ b/app/src/main/res/drawable/gas.xml @@ -0,0 +1,27 @@ + + + + + + + + + diff --git a/app/src/main/res/drawable/groceries.xml b/app/src/main/res/drawable/groceries.xml new file mode 100644 index 0000000..cf2bcf7 --- /dev/null +++ b/app/src/main/res/drawable/groceries.xml @@ -0,0 +1,24 @@ + + + + + + + + diff --git a/app/src/main/res/drawable/home_improvement.xml b/app/src/main/res/drawable/home_improvement.xml new file mode 100644 index 0000000..bb90a3a --- /dev/null +++ b/app/src/main/res/drawable/home_improvement.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/hotel.xml b/app/src/main/res/drawable/hotel.xml new file mode 100644 index 0000000..4b624ed --- /dev/null +++ b/app/src/main/res/drawable/hotel.xml @@ -0,0 +1,24 @@ + + + + + + + + diff --git a/app/src/main/res/drawable/others.xml b/app/src/main/res/drawable/others.xml new file mode 100644 index 0000000..39d4284 --- /dev/null +++ b/app/src/main/res/drawable/others.xml @@ -0,0 +1,27 @@ + + + + + diff --git a/app/src/main/res/drawable/pharmacy.xml b/app/src/main/res/drawable/pharmacy.xml new file mode 100644 index 0000000..41cc005 --- /dev/null +++ b/app/src/main/res/drawable/pharmacy.xml @@ -0,0 +1,24 @@ + + + + + + + + diff --git a/app/src/main/res/drawable/restaurants.xml b/app/src/main/res/drawable/restaurants.xml new file mode 100644 index 0000000..8f2b539 --- /dev/null +++ b/app/src/main/res/drawable/restaurants.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/travel.xml b/app/src/main/res/drawable/travel.xml new file mode 100644 index 0000000..223b2ba --- /dev/null +++ b/app/src/main/res/drawable/travel.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + From 07739ae6a72d71420e305406a4326ab031ca32e1 Mon Sep 17 00:00:00 2001 From: Nandini Date: Mon, 15 Jul 2024 22:53:18 -0400 Subject: [PATCH 02/21] purchase page --- .../edu/card/clarity/presentation/Purchase.kt | 131 ++++++++++++++++-- .../presentation/navigation/BottomNavGraph.kt | 6 +- 2 files changed, 126 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/edu/card/clarity/presentation/Purchase.kt b/app/src/main/java/edu/card/clarity/presentation/Purchase.kt index ae1b145..a569a75 100644 --- a/app/src/main/java/edu/card/clarity/presentation/Purchase.kt +++ b/app/src/main/java/edu/card/clarity/presentation/Purchase.kt @@ -1,28 +1,138 @@ package edu.card.clarity.presentation +import androidx.compose.foundation.Image import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.navigation.NavController +import androidx.navigation.compose.rememberNavController +import edu.card.clarity.R @Composable -fun PurchaseScreen() { - Box( +fun PurchaseScreen(navController: NavController) { + Column( modifier = Modifier .fillMaxSize() - .background(Color.Black), - contentAlignment = Alignment.Center + .background(Color.White) + .padding(horizontal = 32.dp, vertical = 40.dp), + horizontalAlignment = Alignment.Start, + verticalArrangement = Arrangement.Top ) { Text( - text = "PURCHASE", + text = "Best Card for Every Purchase", fontWeight = FontWeight.Bold, - color = Color.White + fontSize = 22.sp, + color = Color.Black + ) + + Spacer(modifier = Modifier.height(24.dp)) + + Text( + text = "Categories:", + fontWeight = FontWeight.Normal, + fontSize = 18.sp, + color = Color.Black + ) + + Spacer(modifier = Modifier.height(24.dp)) + + CategoryGrid(navController) + } +} + +@Composable +fun CategoryGrid(navController: NavController) { + val categories = listOf( + "Pharmacy", + "Entertainment", + "Furniture", + "Gas", + "Hotel", + "Home Improvement", + "Groceries", + "Restaurants", + "Travel", + "Others" + ) + + Column { + for (i in categories.indices step 3) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween + ) { + for (j in i until i + 3) { + if (j < categories.size) { + CategoryCard(category = categories[j]) { + navController.navigate("benefits/${categories[j]}") + } + } else { + Spacer(modifier = Modifier.size(100.dp)) + } + } + } + } + } +} + +@Composable +fun CategoryCard(category: String, onClick: () -> Unit) { + Column( + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center, + modifier = Modifier + .padding(4.dp) + .clickable(onClick = onClick) + ) { + Box( + contentAlignment = Alignment.Center, + modifier = Modifier + .size(100.dp) + .clip(RoundedCornerShape(8.dp)) + .background(Color.LightGray) + ) { + val imageRes = when (category) { + "Pharmacy" -> R.drawable.pharmacy + "Entertainment" -> R.drawable.entertainment + "Furniture" -> R.drawable.furniture + "Gas" -> R.drawable.gas + "Hotel" -> R.drawable.hotel + "Home Improvement" -> R.drawable.home_improvement + "Groceries" -> R.drawable.groceries + "Restaurants" -> R.drawable.restaurants + "Travel" -> R.drawable.travel + "Others" -> R.drawable.others + else -> null + } + if (imageRes != null) { + Image( + painter = painterResource(id = imageRes), + contentDescription = category, + modifier = Modifier.size(64.dp) + ) + } + } + Spacer(modifier = Modifier.height(8.dp)) + Text( + text = category, + fontSize = 14.sp, + fontWeight = FontWeight.Normal, + color = Color.Black, + textAlign = TextAlign.Center, + modifier = Modifier.padding(horizontal = 4.dp) ) } } @@ -30,5 +140,6 @@ fun PurchaseScreen() { @Composable @Preview fun PurchaseScreenPreview() { - PurchaseScreen() -} \ No newline at end of file + val navController = rememberNavController() + PurchaseScreen(navController) +} diff --git a/app/src/main/java/edu/card/clarity/presentation/navigation/BottomNavGraph.kt b/app/src/main/java/edu/card/clarity/presentation/navigation/BottomNavGraph.kt index 636ca4b..addda98 100644 --- a/app/src/main/java/edu/card/clarity/presentation/navigation/BottomNavGraph.kt +++ b/app/src/main/java/edu/card/clarity/presentation/navigation/BottomNavGraph.kt @@ -4,6 +4,7 @@ import androidx.compose.runtime.Composable import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable +import edu.card.clarity.presentation.BenefitsScreen import edu.card.clarity.presentation.addCardScreen.AddCardScreen import edu.card.clarity.presentation.HomeScreen import edu.card.clarity.presentation.MyBenefitsScreen @@ -27,7 +28,7 @@ fun BottomNavGraph(navController: NavHostController) { MyBenefitsScreen() } composable(route = BottomNavBar.Purchase.route) { - PurchaseScreen() + PurchaseScreen(navController) } composable("myCards") { MyCardsScreen() @@ -35,5 +36,8 @@ fun BottomNavGraph(navController: NavHostController) { composable("upcomingPayments") { UpcomingPaymentsScreen() } + composable("benefits/{category}") { backStackEntry -> + BenefitsScreen(navController, category = backStackEntry.arguments?.getString("category") ?: "") + } } } \ No newline at end of file From 4c9422d4cd011a59d3462f862007b9ce538485f0 Mon Sep 17 00:00:00 2001 From: Nandini Date: Wed, 17 Jul 2024 17:24:57 -0400 Subject: [PATCH 03/21] view model changes - purchase benefits screen --- .../presentation/navigation/BottomNavGraph.kt | 2 +- .../BenefitsPage.kt | 42 ++++++++++++-- .../BenefitsPageViewModel.kt | 58 +++++++++++++++++++ 3 files changed, 95 insertions(+), 7 deletions(-) rename app/src/main/java/edu/card/clarity/presentation/{ => purchaseBenefitsScreen}/BenefitsPage.kt (50%) create mode 100644 app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/BenefitsPageViewModel.kt diff --git a/app/src/main/java/edu/card/clarity/presentation/navigation/BottomNavGraph.kt b/app/src/main/java/edu/card/clarity/presentation/navigation/BottomNavGraph.kt index addda98..e3b091c 100644 --- a/app/src/main/java/edu/card/clarity/presentation/navigation/BottomNavGraph.kt +++ b/app/src/main/java/edu/card/clarity/presentation/navigation/BottomNavGraph.kt @@ -4,7 +4,7 @@ import androidx.compose.runtime.Composable import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable -import edu.card.clarity.presentation.BenefitsScreen +import edu.card.clarity.presentation.purchaseBenefitsScreen.BenefitsScreen import edu.card.clarity.presentation.addCardScreen.AddCardScreen import edu.card.clarity.presentation.HomeScreen import edu.card.clarity.presentation.MyBenefitsScreen diff --git a/app/src/main/java/edu/card/clarity/presentation/BenefitsPage.kt b/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/BenefitsPage.kt similarity index 50% rename from app/src/main/java/edu/card/clarity/presentation/BenefitsPage.kt rename to app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/BenefitsPage.kt index f9a23f7..d42ff5b 100644 --- a/app/src/main/java/edu/card/clarity/presentation/BenefitsPage.kt +++ b/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/BenefitsPage.kt @@ -1,26 +1,35 @@ -package edu.card.clarity.presentation + +package edu.card.clarity.presentation.purchaseBenefitsScreen import androidx.compose.foundation.background import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavController import androidx.navigation.compose.rememberNavController +import edu.card.clarity.presentation.purchaseBenefitsScreen.BenefitsPageViewModel.CreditCardItemUiState @Composable -fun BenefitsScreen(navController: NavController, category: String) { +fun BenefitsScreen(navController: NavController, category: String, viewModel: BenefitsPageViewModel = hiltViewModel()) { + val creditCards by viewModel.creditCards.collectAsState() + Column( modifier = Modifier .fillMaxSize() .background(Color.White) .padding(horizontal = 32.dp, vertical = 40.dp), - ) { + ) { Text( text = "Benefits for $category", fontWeight = FontWeight.Bold, @@ -29,12 +38,33 @@ fun BenefitsScreen(navController: NavController, category: String) { ) Spacer(modifier = Modifier.height(24.dp)) + + LazyColumn { + items(creditCards) { card -> + CreditCardItem(card) + } + } + } +} + +@Composable +fun CreditCardItem(card: CreditCardItemUiState) { + Column(modifier = Modifier.padding(vertical = 8.dp)) { Text( - text = "List of benefits based on saved cards for $category", - fontWeight = FontWeight.Normal, + text = "Card: ${card.name}", + fontWeight = FontWeight.Bold, fontSize = 18.sp, color = Color.Black ) + Spacer(modifier = Modifier.height(4.dp)) + card.rewards.forEach { reward -> + Text( + text = "Benefit: ${reward.purchaseType} - ${reward.percentage}%", + fontWeight = FontWeight.Normal, + fontSize = 16.sp, + color = Color.Black + ) + } } } @@ -43,4 +73,4 @@ fun BenefitsScreen(navController: NavController, category: String) { fun BenefitsScreenPreview() { val navController = rememberNavController() BenefitsScreen(navController, category = "Pharmacy") -} +} \ No newline at end of file diff --git a/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/BenefitsPageViewModel.kt b/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/BenefitsPageViewModel.kt new file mode 100644 index 0000000..7bb0296 --- /dev/null +++ b/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/BenefitsPageViewModel.kt @@ -0,0 +1,58 @@ +package edu.card.clarity.presentation.purchaseBenefitsScreen + +import android.util.Log +import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import dagger.hilt.android.lifecycle.HiltViewModel +import edu.card.clarity.domain.creditCard.CashBackCreditCard +import edu.card.clarity.repositories.creditCard.CashBackCreditCardRepository +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class BenefitsPageViewModel @Inject constructor( + private val cashBackCreditCardRepository: CashBackCreditCardRepository, + private val savedStateHandle: SavedStateHandle +) : ViewModel() { + + private val _creditCards = MutableStateFlow>(emptyList()) + val creditCards: StateFlow> = _creditCards + + init { + fetchCreditCards() + } + + private fun fetchCreditCards() { + viewModelScope.launch { + cashBackCreditCardRepository.getAllCreditCardsStream().collect { cards -> + cards.forEach { card -> + Log.d("BenefitsPageViewModel", "Fetched card: $card") + } + _creditCards.value = cards.map { it.toUiState() } + } + } + } + + private fun CashBackCreditCard.toUiState() = CreditCardItemUiState( + name = this.info.name, + rewards = this.purchaseRewards.map { reward -> + RewardUiState( + purchaseType = reward.applicablePurchaseType.toString(), + percentage = reward.rewardFactor * 100 + ) + } + ) + + data class CreditCardItemUiState( + val name: String, + val rewards: List + ) + + data class RewardUiState( + val purchaseType: String, + val percentage: Float + ) +} \ No newline at end of file From afdc9eca94158759eb84dae748d3fa25ad03806d Mon Sep 17 00:00:00 2001 From: Nandini Date: Wed, 17 Jul 2024 20:37:25 -0400 Subject: [PATCH 04/21] UI enhancements --- .../purchaseBenefitsScreen/BenefitsPage.kt | 57 ++++++++++++------- 1 file changed, 35 insertions(+), 22 deletions(-) diff --git a/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/BenefitsPage.kt b/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/BenefitsPage.kt index d42ff5b..6078019 100644 --- a/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/BenefitsPage.kt +++ b/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/BenefitsPage.kt @@ -1,11 +1,10 @@ - package edu.card.clarity.presentation.purchaseBenefitsScreen import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items -import androidx.compose.material3.Text +import androidx.compose.material3.* import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue @@ -28,18 +27,20 @@ fun BenefitsScreen(navController: NavController, category: String, viewModel: Be modifier = Modifier .fillMaxSize() .background(Color.White) - .padding(horizontal = 32.dp, vertical = 40.dp), + .padding(horizontal = 16.dp, vertical = 20.dp), ) { Text( text = "Benefits for $category", fontWeight = FontWeight.Bold, - fontSize = 22.sp, - color = Color.Black + fontSize = 24.sp, + color = Color.Black, + modifier = Modifier.padding(vertical = 16.dp) ) - Spacer(modifier = Modifier.height(24.dp)) - - LazyColumn { + LazyColumn( + verticalArrangement = Arrangement.spacedBy(16.dp), + contentPadding = PaddingValues(bottom = 16.dp) + ) { items(creditCards) { card -> CreditCardItem(card) } @@ -49,21 +50,33 @@ fun BenefitsScreen(navController: NavController, category: String, viewModel: Be @Composable fun CreditCardItem(card: CreditCardItemUiState) { - Column(modifier = Modifier.padding(vertical = 8.dp)) { - Text( - text = "Card: ${card.name}", - fontWeight = FontWeight.Bold, - fontSize = 18.sp, - color = Color.Black - ) - Spacer(modifier = Modifier.height(4.dp)) - card.rewards.forEach { reward -> + Card( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 8.dp), + elevation = CardDefaults.elevatedCardElevation(4.dp), + shape = MaterialTheme.shapes.medium + ) { + Column( + modifier = Modifier + .background(Color.White) + .padding(16.dp) + ) { Text( - text = "Benefit: ${reward.purchaseType} - ${reward.percentage}%", - fontWeight = FontWeight.Normal, - fontSize = 16.sp, - color = Color.Black + text = card.name, + fontWeight = FontWeight.Bold, + fontSize = 20.sp, + color = MaterialTheme.colorScheme.primary ) + Spacer(modifier = Modifier.height(8.dp)) + card.rewards.forEach { reward -> + Text( + text = "${reward.purchaseType} - ${reward.percentage}%", + fontSize = 16.sp, + color = Color.Black + ) + HorizontalDivider(modifier = Modifier.padding(vertical = 4.dp)) + } } } } @@ -73,4 +86,4 @@ fun CreditCardItem(card: CreditCardItemUiState) { fun BenefitsScreenPreview() { val navController = rememberNavController() BenefitsScreen(navController, category = "Pharmacy") -} \ No newline at end of file +} From 5b6c65779a1e987f5794fcd3605e922a573f3cc2 Mon Sep 17 00:00:00 2001 From: Nandini Date: Fri, 19 Jul 2024 16:11:46 -0400 Subject: [PATCH 05/21] display benefits on cards on revalent purchase pages --- .../purchaseBenefitsScreen/BenefitsPage.kt | 13 +++++++++- .../BenefitsPageViewModel.kt | 25 +++++++++++++------ 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/BenefitsPage.kt b/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/BenefitsPage.kt index 6078019..06486f0 100644 --- a/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/BenefitsPage.kt +++ b/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/BenefitsPage.kt @@ -27,7 +27,7 @@ fun BenefitsScreen(navController: NavController, category: String, viewModel: Be modifier = Modifier .fillMaxSize() .background(Color.White) - .padding(horizontal = 16.dp, vertical = 20.dp), + .padding(horizontal = 16.dp, vertical = 20.dp) ) { Text( text = "Benefits for $category", @@ -44,6 +44,17 @@ fun BenefitsScreen(navController: NavController, category: String, viewModel: Be items(creditCards) { card -> CreditCardItem(card) } + item { + Spacer(modifier = Modifier.height(16.dp)) + Button( + onClick = { /* Navigate to record receipt screen */ }, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 8.dp) + ) { + Text(text = "Record a Receipt") + } + } } } } diff --git a/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/BenefitsPageViewModel.kt b/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/BenefitsPageViewModel.kt index 7bb0296..246f670 100644 --- a/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/BenefitsPageViewModel.kt +++ b/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/BenefitsPageViewModel.kt @@ -22,16 +22,27 @@ class BenefitsPageViewModel @Inject constructor( val creditCards: StateFlow> = _creditCards init { - fetchCreditCards() + val category = savedStateHandle.get("category") ?: "" + fetchCreditCards(category) } - private fun fetchCreditCards() { + private fun fetchCreditCards(category: String) { viewModelScope.launch { cashBackCreditCardRepository.getAllCreditCardsStream().collect { cards -> - cards.forEach { card -> - Log.d("BenefitsPageViewModel", "Fetched card: $card") - } - _creditCards.value = cards.map { it.toUiState() } + val filteredCards = cards.map { card -> + card.toUiState().copy( + rewards = card.purchaseRewards.filter { reward -> + reward.applicablePurchaseType.toString().equals(category, ignoreCase = true) + }.map { reward -> + RewardUiState( + purchaseType = reward.applicablePurchaseType.toString(), + percentage = reward.rewardFactor * 100 + ) + } + ) + }.filter { it.rewards.isNotEmpty() } + + _creditCards.value = filteredCards } } } @@ -55,4 +66,4 @@ class BenefitsPageViewModel @Inject constructor( val purchaseType: String, val percentage: Float ) -} \ No newline at end of file +} From 0921c257e39ce8598241924f7789026811908a88 Mon Sep 17 00:00:00 2001 From: Nandini Date: Mon, 22 Jul 2024 20:51:43 -0400 Subject: [PATCH 06/21] fixing nav errors + file renaming --- .../java/edu/card/clarity/presentation/Purchase.kt | 3 ++- .../clarity/presentation/navigation/BottomNavGraph.kt | 10 +++++++++- ...nefitsPage.kt => PurchaseOptimalBenefitsScreen.kt} | 11 +++++++---- ...l.kt => PurchaseOptimalBenefitsScreenViewModel.kt} | 2 +- .../card/clarity/presentation/utils/Destinations.kt | 1 + 5 files changed, 20 insertions(+), 7 deletions(-) rename app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/{BenefitsPage.kt => PurchaseOptimalBenefitsScreen.kt} (90%) rename app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/{BenefitsPageViewModel.kt => PurchaseOptimalBenefitsScreenViewModel.kt} (97%) diff --git a/app/src/main/java/edu/card/clarity/presentation/Purchase.kt b/app/src/main/java/edu/card/clarity/presentation/Purchase.kt index a569a75..1fe768b 100644 --- a/app/src/main/java/edu/card/clarity/presentation/Purchase.kt +++ b/app/src/main/java/edu/card/clarity/presentation/Purchase.kt @@ -20,6 +20,7 @@ import androidx.compose.ui.unit.sp import androidx.navigation.NavController import androidx.navigation.compose.rememberNavController import edu.card.clarity.R +import edu.card.clarity.presentation.utils.Destinations @Composable fun PurchaseScreen(navController: NavController) { @@ -77,7 +78,7 @@ fun CategoryGrid(navController: NavController) { for (j in i until i + 3) { if (j < categories.size) { CategoryCard(category = categories[j]) { - navController.navigate("benefits/${categories[j]}") + navController.navigate("${Destinations.PURCHASE_OPTIMAL_BENEFITS}/${categories[j]}") } } else { Spacer(modifier = Modifier.size(100.dp)) diff --git a/app/src/main/java/edu/card/clarity/presentation/navigation/BottomNavGraph.kt b/app/src/main/java/edu/card/clarity/presentation/navigation/BottomNavGraph.kt index 2cb0ee7..0d352fa 100644 --- a/app/src/main/java/edu/card/clarity/presentation/navigation/BottomNavGraph.kt +++ b/app/src/main/java/edu/card/clarity/presentation/navigation/BottomNavGraph.kt @@ -16,6 +16,7 @@ import edu.card.clarity.presentation.addBenefitScreen.AddBenefitScreen import edu.card.clarity.presentation.addCardScreen.AddCardScreen import edu.card.clarity.presentation.myBenefitsScreen.MyBenefitsScreen import edu.card.clarity.presentation.myCardScreen.MyCardsScreen +import edu.card.clarity.presentation.purchaseBenefitsScreen.PurchaseOptimalBenefitsScreen import edu.card.clarity.presentation.utils.ArgumentNames import edu.card.clarity.presentation.utils.Destinations @@ -35,7 +36,7 @@ fun BottomNavGraph(navController: NavHostController) { MyReceiptsScreen() } composable(Destinations.PURCHASE) { - PurchaseScreen() + PurchaseScreen(navController) } composable(Destinations.MY_CARDS) { MyCardsScreen(navController) @@ -91,5 +92,12 @@ fun BottomNavGraph(navController: NavHostController) { AddBenefitScreen(cardName) } + composable( + route = "${Destinations.PURCHASE_OPTIMAL_BENEFITS}/{category}", + arguments = listOf(navArgument("category") { type = NavType.StringType }) + ) { backStackEntry -> + val category = backStackEntry.arguments?.getString("category")!! + PurchaseOptimalBenefitsScreen(navController, category) + } } } diff --git a/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/BenefitsPage.kt b/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/PurchaseOptimalBenefitsScreen.kt similarity index 90% rename from app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/BenefitsPage.kt rename to app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/PurchaseOptimalBenefitsScreen.kt index 06486f0..36e8f08 100644 --- a/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/BenefitsPage.kt +++ b/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/PurchaseOptimalBenefitsScreen.kt @@ -17,10 +17,13 @@ import androidx.compose.ui.unit.sp import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavController import androidx.navigation.compose.rememberNavController -import edu.card.clarity.presentation.purchaseBenefitsScreen.BenefitsPageViewModel.CreditCardItemUiState @Composable -fun BenefitsScreen(navController: NavController, category: String, viewModel: BenefitsPageViewModel = hiltViewModel()) { +fun PurchaseOptimalBenefitsScreen( + navController: NavController, + category: String, + viewModel: PurchaseOptimalBenefitsScreenViewModel = hiltViewModel() +) { val creditCards by viewModel.creditCards.collectAsState() Column( @@ -60,7 +63,7 @@ fun BenefitsScreen(navController: NavController, category: String, viewModel: Be } @Composable -fun CreditCardItem(card: CreditCardItemUiState) { +fun CreditCardItem(card: PurchaseOptimalBenefitsScreenViewModel.CreditCardItemUiState) { Card( modifier = Modifier .fillMaxWidth() @@ -96,5 +99,5 @@ fun CreditCardItem(card: CreditCardItemUiState) { @Preview fun BenefitsScreenPreview() { val navController = rememberNavController() - BenefitsScreen(navController, category = "Pharmacy") + PurchaseOptimalBenefitsScreen(navController, category = "Pharmacy") } diff --git a/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/BenefitsPageViewModel.kt b/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/PurchaseOptimalBenefitsScreenViewModel.kt similarity index 97% rename from app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/BenefitsPageViewModel.kt rename to app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/PurchaseOptimalBenefitsScreenViewModel.kt index 246f670..b1484c2 100644 --- a/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/BenefitsPageViewModel.kt +++ b/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/PurchaseOptimalBenefitsScreenViewModel.kt @@ -13,7 +13,7 @@ import kotlinx.coroutines.launch import javax.inject.Inject @HiltViewModel -class BenefitsPageViewModel @Inject constructor( +class PurchaseOptimalBenefitsScreenViewModel @Inject constructor( private val cashBackCreditCardRepository: CashBackCreditCardRepository, private val savedStateHandle: SavedStateHandle ) : ViewModel() { diff --git a/app/src/main/java/edu/card/clarity/presentation/utils/Destinations.kt b/app/src/main/java/edu/card/clarity/presentation/utils/Destinations.kt index ad1552d..bee16d6 100644 --- a/app/src/main/java/edu/card/clarity/presentation/utils/Destinations.kt +++ b/app/src/main/java/edu/card/clarity/presentation/utils/Destinations.kt @@ -9,4 +9,5 @@ internal object Destinations { const val UPCOMING_PAYMENTS = "upcomingPayments" const val MY_BENEFITS = "myBenefits" const val ADD_BENEFIT = "addBenefit" + const val PURCHASE_OPTIMAL_BENEFITS = "purchaseOptimalBenefits" } \ No newline at end of file From c8452da09f989a8cd0fcf9ea81b6f1f54c419e18 Mon Sep 17 00:00:00 2001 From: Nandini Date: Mon, 22 Jul 2024 23:55:26 -0400 Subject: [PATCH 07/21] displaying optimal card for the purchase type --- .../edu/card/clarity/presentation/Purchase.kt | 53 +++--- .../presentation/navigation/BottomNavGraph.kt | 4 +- .../PurchaseOptimalBenefitsScreen.kt | 66 +++++++- .../PurchaseOptimalBenefitsScreenViewModel.kt | 152 +++++++++++++++--- 4 files changed, 212 insertions(+), 63 deletions(-) diff --git a/app/src/main/java/edu/card/clarity/presentation/Purchase.kt b/app/src/main/java/edu/card/clarity/presentation/Purchase.kt index 1fe768b..0f59236 100644 --- a/app/src/main/java/edu/card/clarity/presentation/Purchase.kt +++ b/app/src/main/java/edu/card/clarity/presentation/Purchase.kt @@ -20,6 +20,7 @@ import androidx.compose.ui.unit.sp import androidx.navigation.NavController import androidx.navigation.compose.rememberNavController import edu.card.clarity.R +import edu.card.clarity.enums.PurchaseType import edu.card.clarity.presentation.utils.Destinations @Composable @@ -56,18 +57,7 @@ fun PurchaseScreen(navController: NavController) { @Composable fun CategoryGrid(navController: NavController) { - val categories = listOf( - "Pharmacy", - "Entertainment", - "Furniture", - "Gas", - "Hotel", - "Home Improvement", - "Groceries", - "Restaurants", - "Travel", - "Others" - ) + val categories = PurchaseType.entries Column { for (i in categories.indices step 3) { @@ -78,7 +68,7 @@ fun CategoryGrid(navController: NavController) { for (j in i until i + 3) { if (j < categories.size) { CategoryCard(category = categories[j]) { - navController.navigate("${Destinations.PURCHASE_OPTIMAL_BENEFITS}/${categories[j]}") + navController.navigate("${Destinations.PURCHASE_OPTIMAL_BENEFITS}/${categories[j].name}") } } else { Spacer(modifier = Modifier.size(100.dp)) @@ -90,7 +80,7 @@ fun CategoryGrid(navController: NavController) { } @Composable -fun CategoryCard(category: String, onClick: () -> Unit) { +fun CategoryCard(category: PurchaseType, onClick: () -> Unit) { Column( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, @@ -106,29 +96,26 @@ fun CategoryCard(category: String, onClick: () -> Unit) { .background(Color.LightGray) ) { val imageRes = when (category) { - "Pharmacy" -> R.drawable.pharmacy - "Entertainment" -> R.drawable.entertainment - "Furniture" -> R.drawable.furniture - "Gas" -> R.drawable.gas - "Hotel" -> R.drawable.hotel - "Home Improvement" -> R.drawable.home_improvement - "Groceries" -> R.drawable.groceries - "Restaurants" -> R.drawable.restaurants - "Travel" -> R.drawable.travel - "Others" -> R.drawable.others - else -> null - } - if (imageRes != null) { - Image( - painter = painterResource(id = imageRes), - contentDescription = category, - modifier = Modifier.size(64.dp) - ) + PurchaseType.Pharmacy -> R.drawable.pharmacy + PurchaseType.Entertainment -> R.drawable.entertainment + PurchaseType.Furniture -> R.drawable.furniture + PurchaseType.Gas -> R.drawable.gas + PurchaseType.Hotel -> R.drawable.hotel + PurchaseType.HomeImprovement -> R.drawable.home_improvement + PurchaseType.Groceries -> R.drawable.groceries + PurchaseType.Restaurants -> R.drawable.restaurants + PurchaseType.Travel -> R.drawable.travel + PurchaseType.Others -> R.drawable.others } + Image( + painter = painterResource(id = imageRes), + contentDescription = category.name, + modifier = Modifier.size(64.dp) + ) } Spacer(modifier = Modifier.height(8.dp)) Text( - text = category, + text = category.name, fontSize = 14.sp, fontWeight = FontWeight.Normal, color = Color.Black, diff --git a/app/src/main/java/edu/card/clarity/presentation/navigation/BottomNavGraph.kt b/app/src/main/java/edu/card/clarity/presentation/navigation/BottomNavGraph.kt index 0d352fa..229112d 100644 --- a/app/src/main/java/edu/card/clarity/presentation/navigation/BottomNavGraph.kt +++ b/app/src/main/java/edu/card/clarity/presentation/navigation/BottomNavGraph.kt @@ -6,6 +6,7 @@ import androidx.navigation.NavType import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.navArgument +import edu.card.clarity.enums.PurchaseType import edu.card.clarity.presentation.MyReceiptsScreen import edu.card.clarity.presentation.addCardScreen.AddCardScreen import edu.card.clarity.presentation.homeScreen.HomeScreen @@ -96,7 +97,8 @@ fun BottomNavGraph(navController: NavHostController) { route = "${Destinations.PURCHASE_OPTIMAL_BENEFITS}/{category}", arguments = listOf(navArgument("category") { type = NavType.StringType }) ) { backStackEntry -> - val category = backStackEntry.arguments?.getString("category")!! + val categoryString = backStackEntry.arguments?.getString("category")!! + val category = PurchaseType.valueOf(categoryString) PurchaseOptimalBenefitsScreen(navController, category) } } diff --git a/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/PurchaseOptimalBenefitsScreen.kt b/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/PurchaseOptimalBenefitsScreen.kt index 36e8f08..2435fcd 100644 --- a/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/PurchaseOptimalBenefitsScreen.kt +++ b/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/PurchaseOptimalBenefitsScreen.kt @@ -17,14 +17,17 @@ import androidx.compose.ui.unit.sp import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavController import androidx.navigation.compose.rememberNavController +import edu.card.clarity.enums.PurchaseType @Composable fun PurchaseOptimalBenefitsScreen( navController: NavController, - category: String, + category: PurchaseType, viewModel: PurchaseOptimalBenefitsScreenViewModel = hiltViewModel() ) { val creditCards by viewModel.creditCards.collectAsState() + val optimalCreditCard by viewModel.optimalCreditCard.collectAsState() + val optimalCardMessage by viewModel.optimalCardMessage.collectAsState() Column( modifier = Modifier @@ -33,7 +36,28 @@ fun PurchaseOptimalBenefitsScreen( .padding(horizontal = 16.dp, vertical = 20.dp) ) { Text( - text = "Benefits for $category", + text = "Best Card for ${category.name}", + fontWeight = FontWeight.Bold, + fontSize = 24.sp, + color = Color.Black, + modifier = Modifier.padding(vertical = 16.dp) + ) + + if (optimalCreditCard != null) { + OptimalCreditCardItem(optimalCreditCard!!, category) + Spacer(modifier = Modifier.height(16.dp)) + } else { + Text( + text = optimalCardMessage ?: "", + fontWeight = FontWeight.Normal, + fontSize = 16.sp, + color = Color.Red, + modifier = Modifier.padding(vertical = 16.dp) + ) + } + + Text( + text = "Other Available Benefits for ${category.name}", fontWeight = FontWeight.Bold, fontSize = 24.sp, color = Color.Black, @@ -62,6 +86,40 @@ fun PurchaseOptimalBenefitsScreen( } } +@Composable +fun OptimalCreditCardItem(card: PurchaseOptimalBenefitsScreenViewModel.CreditCardItemUiState, category: PurchaseType) { + Card( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 8.dp), + elevation = CardDefaults.elevatedCardElevation(4.dp), + shape = MaterialTheme.shapes.medium + ) { + Column( + modifier = Modifier + .background(Color.LightGray) + .padding(16.dp) + ) { + Text( + text = card.name, + fontWeight = FontWeight.Bold, + fontSize = 20.sp, + color = MaterialTheme.colorScheme.primary + ) + Spacer(modifier = Modifier.height(8.dp)) + + card.rewards.forEach { reward -> + Text( + text = "${reward.purchaseType} - ${reward.description}", + fontSize = 16.sp, + color = Color.Black + ) + HorizontalDivider(modifier = Modifier.padding(vertical = 4.dp)) + } + } + } +} + @Composable fun CreditCardItem(card: PurchaseOptimalBenefitsScreenViewModel.CreditCardItemUiState) { Card( @@ -85,7 +143,7 @@ fun CreditCardItem(card: PurchaseOptimalBenefitsScreenViewModel.CreditCardItemUi Spacer(modifier = Modifier.height(8.dp)) card.rewards.forEach { reward -> Text( - text = "${reward.purchaseType} - ${reward.percentage}%", + text = "${reward.purchaseType} - ${reward.description}", fontSize = 16.sp, color = Color.Black ) @@ -99,5 +157,5 @@ fun CreditCardItem(card: PurchaseOptimalBenefitsScreenViewModel.CreditCardItemUi @Preview fun BenefitsScreenPreview() { val navController = rememberNavController() - PurchaseOptimalBenefitsScreen(navController, category = "Pharmacy") + PurchaseOptimalBenefitsScreen(navController, category = PurchaseType.Pharmacy) } diff --git a/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/PurchaseOptimalBenefitsScreenViewModel.kt b/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/PurchaseOptimalBenefitsScreenViewModel.kt index b1484c2..53b5310 100644 --- a/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/PurchaseOptimalBenefitsScreenViewModel.kt +++ b/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/PurchaseOptimalBenefitsScreenViewModel.kt @@ -1,61 +1,163 @@ package edu.card.clarity.presentation.purchaseBenefitsScreen -import android.util.Log import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel -import edu.card.clarity.domain.creditCard.CashBackCreditCard +import edu.card.clarity.domain.Purchase +import edu.card.clarity.enums.PurchaseType +import edu.card.clarity.enums.RewardType import edu.card.clarity.repositories.creditCard.CashBackCreditCardRepository +import edu.card.clarity.repositories.creditCard.PointBackCreditCardRepository import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch +import java.util.* import javax.inject.Inject @HiltViewModel class PurchaseOptimalBenefitsScreenViewModel @Inject constructor( private val cashBackCreditCardRepository: CashBackCreditCardRepository, - private val savedStateHandle: SavedStateHandle + private val pointBackCreditCardRepository: PointBackCreditCardRepository, + savedStateHandle: SavedStateHandle ) : ViewModel() { + private val category: PurchaseType = PurchaseType.valueOf(savedStateHandle.get("category") ?: "") + private val _creditCards = MutableStateFlow>(emptyList()) val creditCards: StateFlow> = _creditCards + private val _optimalCreditCard = MutableStateFlow(null) + val optimalCreditCard: StateFlow = _optimalCreditCard + + private val _optimalCardMessage = MutableStateFlow(null) + val optimalCardMessage: StateFlow = _optimalCardMessage + init { - val category = savedStateHandle.get("category") ?: "" fetchCreditCards(category) + findOptimalCreditCard(category) } - private fun fetchCreditCards(category: String) { + private fun fetchCreditCards(category: PurchaseType) { viewModelScope.launch { - cashBackCreditCardRepository.getAllCreditCardsStream().collect { cards -> - val filteredCards = cards.map { card -> - card.toUiState().copy( - rewards = card.purchaseRewards.filter { reward -> - reward.applicablePurchaseType.toString().equals(category, ignoreCase = true) - }.map { reward -> - RewardUiState( - purchaseType = reward.applicablePurchaseType.toString(), - percentage = reward.rewardFactor * 100 + val cashBackCardsFlow = cashBackCreditCardRepository.getAllCreditCardsStream().map { cards -> + cards.flatMap { card -> + val rewardsForCategory = card.purchaseRewards.filter { reward -> + reward.applicablePurchaseType == category + } + + val rewards = rewardsForCategory.ifEmpty { + card.purchaseRewards.filter { reward -> + reward.applicablePurchaseType == PurchaseType.Others + } + } + + rewards.map { reward -> + CreditCardItemUiState( + name = card.info.name, + rewards = listOf( + RewardUiState( + purchaseType = reward.applicablePurchaseType.name, + description = "${(reward.rewardFactor * 100).toInt()}% Cashback" + ) ) + ) + } + } + } + + val pointBackCardsFlow = pointBackCreditCardRepository.getAllCreditCardsStream().map { cards -> + cards.flatMap { card -> + val rewardsForCategory = card.purchaseRewards.filter { reward -> + reward.applicablePurchaseType == category + } + + val rewards = rewardsForCategory.ifEmpty { + card.purchaseRewards.filter { reward -> + reward.applicablePurchaseType == PurchaseType.Others } - ) - }.filter { it.rewards.isNotEmpty() } + } + + rewards.map { reward -> + CreditCardItemUiState( + name = card.info.name, + rewards = listOf( + RewardUiState( + purchaseType = reward.applicablePurchaseType.name, + description = "${reward.rewardFactor}x Points" + ) + ) + ) + } + } + } - _creditCards.value = filteredCards + combine(cashBackCardsFlow, pointBackCardsFlow) { cashBackCards, pointBackCards -> + cashBackCards + pointBackCards + }.collect { combinedCards -> + _creditCards.value = combinedCards } } } - private fun CashBackCreditCard.toUiState() = CreditCardItemUiState( - name = this.info.name, - rewards = this.purchaseRewards.map { reward -> - RewardUiState( - purchaseType = reward.applicablePurchaseType.toString(), - percentage = reward.rewardFactor * 100 + private fun findOptimalCreditCard(category: PurchaseType) { + viewModelScope.launch { + val dummyPurchase = Purchase( + id = UUID.randomUUID(), + time = Date(), + merchant = "Dummy Merchant", + type = category, + total = 100f, + rewardAmount = 0f, + creditCardId = UUID.randomUUID() ) + + val optimalCashBackCard = try { + cashBackCreditCardRepository.findOptimalCreditCard(dummyPurchase) + } catch (e: NoSuchElementException) { + null + } + val optimalPointBackCard = try { + pointBackCreditCardRepository.findOptimalCreditCard(dummyPurchase) + } catch (e: NoSuchElementException) { + null + } + + val optimalCard = listOfNotNull(optimalCashBackCard, optimalPointBackCard).maxByOrNull { + it.getReturnAmountInCash(dummyPurchase) + } + + // The Optimal Card's corresponding benefit that makes it optimal + optimalCard?.let { card -> + val rewardsForCategory = card.purchaseRewards.filter { reward -> + reward.applicablePurchaseType == category + } + + val rewards = rewardsForCategory.ifEmpty { + card.purchaseRewards.filter { reward -> + reward.applicablePurchaseType == PurchaseType.Others + } + } + + val uiState = CreditCardItemUiState( + name = card.info.name, + rewards = rewards.map { reward -> + RewardUiState( + purchaseType = reward.applicablePurchaseType.name, + description = if (card.info.rewardType == RewardType.CashBack) { + "${(reward.rewardFactor * 100).toInt()}% Cashback" + } else { + "${reward.rewardFactor}x Points" + } + ) + } + ) + _optimalCreditCard.value = uiState + } } - ) + } data class CreditCardItemUiState( val name: String, @@ -64,6 +166,6 @@ class PurchaseOptimalBenefitsScreenViewModel @Inject constructor( data class RewardUiState( val purchaseType: String, - val percentage: Float + val description: String ) } From 59b42e6db013910de34d777d1d669d247dedb2a9 Mon Sep 17 00:00:00 2001 From: Nandini Date: Tue, 23 Jul 2024 01:07:05 -0400 Subject: [PATCH 08/21] display name for HomeImprovement --- .../main/java/edu/card/clarity/presentation/Purchase.kt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/edu/card/clarity/presentation/Purchase.kt b/app/src/main/java/edu/card/clarity/presentation/Purchase.kt index 0f59236..95d4374 100644 --- a/app/src/main/java/edu/card/clarity/presentation/Purchase.kt +++ b/app/src/main/java/edu/card/clarity/presentation/Purchase.kt @@ -58,6 +58,9 @@ fun PurchaseScreen(navController: NavController) { @Composable fun CategoryGrid(navController: NavController) { val categories = PurchaseType.entries + val displayNames = mapOf( + PurchaseType.HomeImprovement to "Home Improvement" + ) Column { for (i in categories.indices step 3) { @@ -67,7 +70,7 @@ fun CategoryGrid(navController: NavController) { ) { for (j in i until i + 3) { if (j < categories.size) { - CategoryCard(category = categories[j]) { + CategoryCard(category = categories[j], displayNames) { navController.navigate("${Destinations.PURCHASE_OPTIMAL_BENEFITS}/${categories[j].name}") } } else { @@ -80,7 +83,7 @@ fun CategoryGrid(navController: NavController) { } @Composable -fun CategoryCard(category: PurchaseType, onClick: () -> Unit) { +fun CategoryCard(category: PurchaseType, displayNames: Map, onClick: () -> Unit) { Column( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, @@ -115,7 +118,7 @@ fun CategoryCard(category: PurchaseType, onClick: () -> Unit) { } Spacer(modifier = Modifier.height(8.dp)) Text( - text = category.name, + text = displayNames[category] ?: category.name, fontSize = 14.sp, fontWeight = FontWeight.Normal, color = Color.Black, From e01bd0e5f94a00c6d103f419fb834426dac3535b Mon Sep 17 00:00:00 2001 From: Nandini Date: Tue, 23 Jul 2024 01:24:17 -0400 Subject: [PATCH 09/21] Enhancing UI of purchase screen --- .../edu/card/clarity/presentation/Purchase.kt | 89 +++++++++++-------- 1 file changed, 52 insertions(+), 37 deletions(-) diff --git a/app/src/main/java/edu/card/clarity/presentation/Purchase.kt b/app/src/main/java/edu/card/clarity/presentation/Purchase.kt index 95d4374..332e0d5 100644 --- a/app/src/main/java/edu/card/clarity/presentation/Purchase.kt +++ b/app/src/main/java/edu/card/clarity/presentation/Purchase.kt @@ -4,12 +4,18 @@ import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* +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.material3.MaterialTheme +import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.draw.shadow import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.font.FontWeight @@ -36,17 +42,17 @@ fun PurchaseScreen(navController: NavController) { Text( text = "Best Card for Every Purchase", fontWeight = FontWeight.Bold, - fontSize = 22.sp, - color = Color.Black + fontSize = 26.sp, + color = MaterialTheme.colorScheme.primary ) Spacer(modifier = Modifier.height(24.dp)) Text( text = "Categories:", - fontWeight = FontWeight.Normal, - fontSize = 18.sp, - color = Color.Black + fontWeight = FontWeight.SemiBold, + fontSize = 20.sp, + color = Color.Gray ) Spacer(modifier = Modifier.height(24.dp)) @@ -62,41 +68,44 @@ fun CategoryGrid(navController: NavController) { PurchaseType.HomeImprovement to "Home Improvement" ) - Column { - for (i in categories.indices step 3) { + LazyColumn { + items(categories.chunked(2)) { rowItems -> Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween ) { - for (j in i until i + 3) { - if (j < categories.size) { - CategoryCard(category = categories[j], displayNames) { - navController.navigate("${Destinations.PURCHASE_OPTIMAL_BENEFITS}/${categories[j].name}") - } - } else { - Spacer(modifier = Modifier.size(100.dp)) + for (category in rowItems) { + CategoryCard(category = category, displayNames) { + navController.navigate("${Destinations.PURCHASE_OPTIMAL_BENEFITS}/${category.name}") } } + if (rowItems.size == 1) { + Spacer(modifier = Modifier.size(150.dp)) + } } + Spacer(modifier = Modifier.height(16.dp)) + } + item { + Spacer(modifier = Modifier.height(32.dp)) } } } @Composable fun CategoryCard(category: PurchaseType, displayNames: Map, onClick: () -> Unit) { - Column( - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Center, + Box( + contentAlignment = Alignment.Center, modifier = Modifier - .padding(4.dp) + .padding(8.dp) + .shadow(4.dp, RoundedCornerShape(16.dp)) .clickable(onClick = onClick) + .clip(RoundedCornerShape(16.dp)) + .background(MaterialTheme.colorScheme.surface) + .size(150.dp) ) { - Box( - contentAlignment = Alignment.Center, - modifier = Modifier - .size(100.dp) - .clip(RoundedCornerShape(8.dp)) - .background(Color.LightGray) + Column( + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center ) { val imageRes = when (category) { PurchaseType.Pharmacy -> R.drawable.pharmacy @@ -110,21 +119,27 @@ fun CategoryCard(category: PurchaseType, displayNames: Map PurchaseType.Travel -> R.drawable.travel PurchaseType.Others -> R.drawable.others } - Image( - painter = painterResource(id = imageRes), - contentDescription = category.name, - modifier = Modifier.size(64.dp) + Surface( + modifier = Modifier.size(100.dp), + shape = CircleShape, + color = MaterialTheme.colorScheme.primary.copy(alpha = 0.2f) + ) { + Image( + painter = painterResource(id = imageRes), + contentDescription = category.name, + modifier = Modifier.padding(20.dp) + ) + } + Spacer(modifier = Modifier.height(8.dp)) + Text( + text = displayNames[category] ?: category.name, + fontSize = 16.sp, + fontWeight = FontWeight.Bold, + color = MaterialTheme.colorScheme.primary, + textAlign = TextAlign.Center, + modifier = Modifier.padding(horizontal = 4.dp) ) } - Spacer(modifier = Modifier.height(8.dp)) - Text( - text = displayNames[category] ?: category.name, - fontSize = 14.sp, - fontWeight = FontWeight.Normal, - color = Color.Black, - textAlign = TextAlign.Center, - modifier = Modifier.padding(horizontal = 4.dp) - ) } } From c97386fd61aca8729f0b1c64823cf19089675407 Mon Sep 17 00:00:00 2001 From: Nandini Date: Tue, 23 Jul 2024 01:32:41 -0400 Subject: [PATCH 10/21] UI improvements - purchase page --- .../PurchaseOptimalBenefitsScreen.kt | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/PurchaseOptimalBenefitsScreen.kt b/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/PurchaseOptimalBenefitsScreen.kt index 2435fcd..325718b 100644 --- a/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/PurchaseOptimalBenefitsScreen.kt +++ b/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/PurchaseOptimalBenefitsScreen.kt @@ -9,6 +9,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.shadow import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview @@ -39,7 +40,7 @@ fun PurchaseOptimalBenefitsScreen( text = "Best Card for ${category.name}", fontWeight = FontWeight.Bold, fontSize = 24.sp, - color = Color.Black, + color = MaterialTheme.colorScheme.primary, modifier = Modifier.padding(vertical = 16.dp) ) @@ -60,7 +61,7 @@ fun PurchaseOptimalBenefitsScreen( text = "Other Available Benefits for ${category.name}", fontWeight = FontWeight.Bold, fontSize = 24.sp, - color = Color.Black, + color = MaterialTheme.colorScheme.primary, modifier = Modifier.padding(vertical = 16.dp) ) @@ -91,13 +92,14 @@ fun OptimalCreditCardItem(card: PurchaseOptimalBenefitsScreenViewModel.CreditCar Card( modifier = Modifier .fillMaxWidth() - .padding(horizontal = 8.dp), + .padding(horizontal = 8.dp) + .shadow(8.dp, shape = MaterialTheme.shapes.medium), elevation = CardDefaults.elevatedCardElevation(4.dp), shape = MaterialTheme.shapes.medium ) { Column( modifier = Modifier - .background(Color.LightGray) + .background(MaterialTheme.colorScheme.surfaceVariant) .padding(16.dp) ) { Text( @@ -125,13 +127,14 @@ fun CreditCardItem(card: PurchaseOptimalBenefitsScreenViewModel.CreditCardItemUi Card( modifier = Modifier .fillMaxWidth() - .padding(horizontal = 8.dp), + .padding(horizontal = 8.dp) + .shadow(8.dp, shape = MaterialTheme.shapes.medium), elevation = CardDefaults.elevatedCardElevation(4.dp), shape = MaterialTheme.shapes.medium ) { Column( modifier = Modifier - .background(Color.White) + .background(MaterialTheme.colorScheme.surface) .padding(16.dp) ) { Text( From a5e47a3af2e8308dede69452bd07a263e3efdece Mon Sep 17 00:00:00 2001 From: Nandini Date: Tue, 23 Jul 2024 18:56:06 -0400 Subject: [PATCH 11/21] integrating geolocation inference --- .../presentation/navigation/BottomNavGraph.kt | 4 +- .../GeolocationViewModel.kt | 33 +++++ .../{ => purchaseBenefitsScreen}/Purchase.kt | 124 +++++++++++++++++- 3 files changed, 153 insertions(+), 8 deletions(-) create mode 100644 app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/GeolocationViewModel.kt rename app/src/main/java/edu/card/clarity/presentation/{ => purchaseBenefitsScreen}/Purchase.kt (53%) diff --git a/app/src/main/java/edu/card/clarity/presentation/navigation/BottomNavGraph.kt b/app/src/main/java/edu/card/clarity/presentation/navigation/BottomNavGraph.kt index 57cce2e..dde5f4b 100644 --- a/app/src/main/java/edu/card/clarity/presentation/navigation/BottomNavGraph.kt +++ b/app/src/main/java/edu/card/clarity/presentation/navigation/BottomNavGraph.kt @@ -11,12 +11,10 @@ import edu.card.clarity.presentation.MyReceiptsScreen import edu.card.clarity.presentation.addCardScreen.AddCardScreen import edu.card.clarity.presentation.homeScreen.HomeScreen import edu.card.clarity.presentation.myCardScreen.MyCardsScreen -import edu.card.clarity.presentation.PurchaseScreen +import edu.card.clarity.presentation.purchaseBenefitsScreen.PurchaseScreen import edu.card.clarity.presentation.UpcomingPaymentsScreen import edu.card.clarity.presentation.addBenefitScreen.AddBenefitScreen -import edu.card.clarity.presentation.addCardScreen.AddCardScreen import edu.card.clarity.presentation.myBenefitsScreen.MyBenefitsScreen -import edu.card.clarity.presentation.myCardScreen.MyCardsScreen import edu.card.clarity.presentation.purchaseBenefitsScreen.PurchaseOptimalBenefitsScreen import edu.card.clarity.presentation.utils.ArgumentNames import edu.card.clarity.presentation.utils.Destinations diff --git a/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/GeolocationViewModel.kt b/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/GeolocationViewModel.kt new file mode 100644 index 0000000..13ad6e6 --- /dev/null +++ b/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/GeolocationViewModel.kt @@ -0,0 +1,33 @@ +package edu.card.clarity.presentation.purchaseBenefitsScreen + +import android.util.Log +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import dagger.hilt.android.lifecycle.HiltViewModel +import edu.card.clarity.location.GeolocationInference +import edu.card.clarity.location.GeolocationInferenceService +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class GeolocationViewModel @Inject constructor( + private val geolocationInferenceService: GeolocationInferenceService +) : ViewModel() { + + private val _geolocationInference = MutableStateFlow?>(null) + val geolocationInference: StateFlow?> = _geolocationInference + + fun fetchGeolocationInference() { + viewModelScope.launch { + try { + val inferences = geolocationInferenceService.getPurchaseTypeInference() + Log.d("Inferences", inferences.toString()) + _geolocationInference.value = inferences + } catch (e: SecurityException) { + // Handle the case where permissions were not granted + } + } + } +} diff --git a/app/src/main/java/edu/card/clarity/presentation/Purchase.kt b/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/Purchase.kt similarity index 53% rename from app/src/main/java/edu/card/clarity/presentation/Purchase.kt rename to app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/Purchase.kt index 332e0d5..4c7a5c5 100644 --- a/app/src/main/java/edu/card/clarity/presentation/Purchase.kt +++ b/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/Purchase.kt @@ -1,5 +1,9 @@ -package edu.card.clarity.presentation +package edu.card.clarity.presentation.purchaseBenefitsScreen +import android.Manifest +import android.content.pm.PackageManager +import androidx.activity.compose.rememberLauncherForActivityResult +import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.clickable @@ -8,29 +12,75 @@ 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.material3.MaterialTheme -import androidx.compose.material3.Surface -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable +import androidx.compose.material3.* +import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.shadow import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import androidx.core.content.ContextCompat +import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavController import androidx.navigation.compose.rememberNavController import edu.card.clarity.R import edu.card.clarity.enums.PurchaseType +import edu.card.clarity.location.GeolocationInference import edu.card.clarity.presentation.utils.Destinations @Composable fun PurchaseScreen(navController: NavController) { + val geolocationViewModel: GeolocationViewModel = hiltViewModel() + val geolocationInference by geolocationViewModel.geolocationInference.collectAsState() + val context = LocalContext.current + + var permissionsGranted by remember { mutableStateOf(false) } + var permissionDenied by remember { mutableStateOf(false) } + + val requestPermissionLauncher = rememberLauncherForActivityResult( + contract = ActivityResultContracts.RequestMultiplePermissions() + ) { permissions -> + permissionsGranted = permissions[Manifest.permission.ACCESS_FINE_LOCATION] == true && + permissions[Manifest.permission.ACCESS_COARSE_LOCATION] == true + permissionDenied = !permissionsGranted + } + + LaunchedEffect(Unit) { + when { + ContextCompat.checkSelfPermission( + context, + Manifest.permission.ACCESS_FINE_LOCATION + ) == PackageManager.PERMISSION_GRANTED && + ContextCompat.checkSelfPermission( + context, + Manifest.permission.ACCESS_COARSE_LOCATION + ) == PackageManager.PERMISSION_GRANTED -> { + permissionsGranted = true + } + else -> { + requestPermissionLauncher.launch( + arrayOf( + Manifest.permission.ACCESS_FINE_LOCATION, + Manifest.permission.ACCESS_COARSE_LOCATION + ) + ) + } + } + } + + if (permissionsGranted) { + LaunchedEffect(Unit) { + geolocationViewModel.fetchGeolocationInference() + } + } + Column( modifier = Modifier .fillMaxSize() @@ -58,6 +108,70 @@ fun PurchaseScreen(navController: NavController) { Spacer(modifier = Modifier.height(24.dp)) CategoryGrid(navController) + + if (permissionsGranted && geolocationInference != null) { + val inference = geolocationInference?.firstOrNull() + if (inference != null) { + GeolocationPopup(inference) + } + } + + if (permissionDenied) { + Text( + text = "Location permissions are required to use this feature.", + color = Color.Red, + modifier = Modifier.padding(top = 16.dp) + ) + } + } +} + +@Composable +fun GeolocationPopup(inference: GeolocationInference) { + Surface( + modifier = Modifier + .fillMaxSize() + .background(Color.Black.copy(alpha = 0.6f)) + .clickable { }, + color = Color.Transparent + ) { + Box( + contentAlignment = Alignment.Center, + modifier = Modifier.fillMaxSize() + ) { + Surface( + shape = RoundedCornerShape(16.dp), + color = Color.White, + modifier = Modifier + .padding(16.dp) + .fillMaxWidth() + ) { + Column( + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center, + modifier = Modifier.padding(16.dp) + ) { + Text( + text = "You are near ${inference.merchantName}", + fontWeight = FontWeight.Bold, + fontSize = 20.sp, + color = MaterialTheme.colorScheme.primary + ) + Spacer(modifier = Modifier.height(16.dp)) + Row( + horizontalArrangement = Arrangement.SpaceEvenly, + modifier = Modifier.fillMaxWidth() + ) { + Button(onClick = { /* TO DO: Handle Yes action */ }) { + Text("Yes") + } + Button(onClick = { /* TO DO: Handle No action */ }) { + Text("No") + } + } + } + } + } } } From 854a7c1c506e128d693d1376b281bbe46578a46f Mon Sep 17 00:00:00 2001 From: Linus Zhang Date: Tue, 23 Jul 2024 19:29:35 -0400 Subject: [PATCH 12/21] Added missing place type mapping data. --- .../database/predefined_credit_cards.db | Bin 69632 -> 77824 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/app/src/main/assets/database/predefined_credit_cards.db b/app/src/main/assets/database/predefined_credit_cards.db index ab075df1738c68340f383a3825fcb7a6e9a74a0a..2cdd88c1e27f9621ff4b9252fb83579a9b2094d1 100644 GIT binary patch delta 1483 zcmaKq!D|~w6o)l_8#}hNGnQ7?TCr706-HJRCm0{v5GbTYO_U}i7##|wtVhyFS}g6V zv$IYVDC@eEUTa+FHIyEEXz3wP3jG5L>7n%2Lr#Gn8tARZ&a50+>liQWvhTg$d-LAB zZ~uw5|6KcOB}rnjm?7U+&-&q&tptf(z5l6B{)?pm9qtx2K=ACx!%t>{&+a7W%z7Oi z5J8)LHtf?DYmA1h;Xd$rt4F=ix<`jY+v%PkO})2WyV=8JLa!WMPUxvg>Q1HdQEJw7>qo2c>^tZ7W^GQg&g|XzysAB|YUt1S+q%4( zW&I#V{vp4UAIR54kZp36WQm4f;y>`u_zC_3`?!Pa_$^$-n*KunMgLAe_$j$~M-K|i zP^tDPZ$G4*S)On?yX_8GeK6$i9vd)6WK1Y$1*dzgZ_zGuTBAm2tY_eQwI{WfeIh=y z!s-%i8Lc*2CSK!c`g@L&lRkHTYVN&kTW}! z4?ICfp=TutTPAxXnA2u$S%Z$Iw<3k6|v7Q;2ODf6h)wwj#L-469c z7+Th$Sd!-p>T~Ld?a7~KCZLq}{2}85%6FN##oZR;HuJJ^DCfJOH5yMd38fbxpKEi! z8(#E-9t~u2Yh=trE;p20P=@r5ofp9aD8rj!lFX1r6p|F ziD(M5uu-N1-wW4gwPYIO5ycx9pfXkjs;D)T14IOuG$@uGyW101tM4}>u^d3TJaG4H zW{Do7r)#gyz}j(`%i6RbNlqdt8C|LvpsMj3x2U(E0LIN2`G$N?GUQ|YH~tGhCI6BS za1(!vza(*j$aC_H{7QE5Z{!NOLH4mv9!Y>N;~)hU6y Date: Tue, 23 Jul 2024 19:49:05 -0400 Subject: [PATCH 13/21] Updated .gitignore to prevent committing secrets. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 347e252..65a2682 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,7 @@ render.experimental.xml # Google Services (e.g. APIs or Firebase) google-services.json +secrets.properties # Android Profiling *.hprof From 1339ff8521ec14441e58a9146c068ffbabf8fda0 Mon Sep 17 00:00:00 2001 From: Nandini Date: Tue, 23 Jul 2024 20:27:55 -0400 Subject: [PATCH 14/21] integrating geolocation + popup UI --- .../GeolocationPopup.kt | 116 +++++++++++++++++ .../purchaseBenefitsScreen/Purchase.kt | 123 ++---------------- 2 files changed, 130 insertions(+), 109 deletions(-) create mode 100644 app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/GeolocationPopup.kt diff --git a/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/GeolocationPopup.kt b/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/GeolocationPopup.kt new file mode 100644 index 0000000..3997089 --- /dev/null +++ b/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/GeolocationPopup.kt @@ -0,0 +1,116 @@ +package edu.card.clarity.presentation.purchaseBenefitsScreen + +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import edu.card.clarity.location.GeolocationInference + +@Composable +fun GeolocationPopup( + geolocationInference: GeolocationInference?, + onDismiss: () -> Unit, + onConfirm: () -> Unit +) { + if (geolocationInference != null) { + AlertDialog( + onDismissRequest = onDismiss, + title = { + Text( + text = "Nearby Merchant Detected", + style = MaterialTheme.typography.headlineMedium, + fontWeight = FontWeight.Bold, + color = MaterialTheme.colorScheme.primary, + textAlign = TextAlign.Center, + modifier = Modifier.fillMaxWidth().padding(top = 16.dp) + ) + }, + text = { + Column( + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center, + modifier = Modifier.padding(vertical = 16.dp) + ) { + Text( + text = "We detected that you're near ", + style = MaterialTheme.typography.bodyLarge, + textAlign = TextAlign.Center, + modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp) + ) + Text( + text = geolocationInference.merchantName, + style = MaterialTheme.typography.bodyLarge, + fontWeight = FontWeight.Bold, + textAlign = TextAlign.Center, + modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp) + ) + Spacer(modifier = Modifier.height(8.dp)) + Text( + text = "Would you like to shop in this purchase type?", + style = MaterialTheme.typography.bodyLarge, + textAlign = TextAlign.Center, + modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp) + ) + } + }, + confirmButton = { + Button( + onClick = onConfirm, + modifier = Modifier.fillMaxWidth().padding(8.dp) + ) { + Text("Yes") + } + }, + dismissButton = { + Button( + onClick = onDismiss, + modifier = Modifier.fillMaxWidth().padding(8.dp) + ) { + Text("No") + } + }, + shape = RoundedCornerShape(16.dp), + containerColor = MaterialTheme.colorScheme.background, + tonalElevation = 8.dp + ) + } else { + AlertDialog( + onDismissRequest = onDismiss, + title = { + Text( + text = "Loading", + style = MaterialTheme.typography.headlineMedium, + fontWeight = FontWeight.Bold, + color = MaterialTheme.colorScheme.primary, + textAlign = TextAlign.Center, + modifier = Modifier.fillMaxWidth().padding(top = 16.dp) + ) + }, + text = { + Box( + contentAlignment = Alignment.Center, + modifier = Modifier.fillMaxWidth().padding(vertical = 16.dp) + ) { + CircularProgressIndicator() + } + }, + confirmButton = { + Button( + onClick = onDismiss, + modifier = Modifier.fillMaxWidth().padding(8.dp) + ) { + Text("Dismiss") + } + }, + dismissButton = {}, + shape = RoundedCornerShape(16.dp), + containerColor = MaterialTheme.colorScheme.background, + tonalElevation = 8.dp + ) + } +} diff --git a/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/Purchase.kt b/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/Purchase.kt index 4c7a5c5..899e501 100644 --- a/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/Purchase.kt +++ b/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/Purchase.kt @@ -1,9 +1,5 @@ package edu.card.clarity.presentation.purchaseBenefitsScreen -import android.Manifest -import android.content.pm.PackageManager -import androidx.activity.compose.rememberLauncherForActivityResult -import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.clickable @@ -19,66 +15,39 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.shadow import androidx.compose.ui.graphics.Color -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import androidx.core.content.ContextCompat import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavController import androidx.navigation.compose.rememberNavController import edu.card.clarity.R import edu.card.clarity.enums.PurchaseType -import edu.card.clarity.location.GeolocationInference import edu.card.clarity.presentation.utils.Destinations @Composable -fun PurchaseScreen(navController: NavController) { - val geolocationViewModel: GeolocationViewModel = hiltViewModel() +fun PurchaseScreen(navController: NavController, geolocationViewModel: GeolocationViewModel = hiltViewModel()) { + var showDialog by remember { mutableStateOf(true) } val geolocationInference by geolocationViewModel.geolocationInference.collectAsState() - val context = LocalContext.current - - var permissionsGranted by remember { mutableStateOf(false) } - var permissionDenied by remember { mutableStateOf(false) } - - val requestPermissionLauncher = rememberLauncherForActivityResult( - contract = ActivityResultContracts.RequestMultiplePermissions() - ) { permissions -> - permissionsGranted = permissions[Manifest.permission.ACCESS_FINE_LOCATION] == true && - permissions[Manifest.permission.ACCESS_COARSE_LOCATION] == true - permissionDenied = !permissionsGranted - } LaunchedEffect(Unit) { - when { - ContextCompat.checkSelfPermission( - context, - Manifest.permission.ACCESS_FINE_LOCATION - ) == PackageManager.PERMISSION_GRANTED && - ContextCompat.checkSelfPermission( - context, - Manifest.permission.ACCESS_COARSE_LOCATION - ) == PackageManager.PERMISSION_GRANTED -> { - permissionsGranted = true - } - else -> { - requestPermissionLauncher.launch( - arrayOf( - Manifest.permission.ACCESS_FINE_LOCATION, - Manifest.permission.ACCESS_COARSE_LOCATION - ) - ) - } - } + geolocationViewModel.fetchGeolocationInference() } - if (permissionsGranted) { - LaunchedEffect(Unit) { - geolocationViewModel.fetchGeolocationInference() - } + if (showDialog) { + GeolocationPopup( + geolocationInference = geolocationInference?.firstOrNull(), + onDismiss = { showDialog = false }, + onConfirm = { + showDialog = false + geolocationInference?.firstOrNull()?.purchaseType?.let { purchaseType -> + navController.navigate("${Destinations.PURCHASE_OPTIMAL_BENEFITS}/${purchaseType.name}") + } + } + ) } Column( @@ -108,70 +77,6 @@ fun PurchaseScreen(navController: NavController) { Spacer(modifier = Modifier.height(24.dp)) CategoryGrid(navController) - - if (permissionsGranted && geolocationInference != null) { - val inference = geolocationInference?.firstOrNull() - if (inference != null) { - GeolocationPopup(inference) - } - } - - if (permissionDenied) { - Text( - text = "Location permissions are required to use this feature.", - color = Color.Red, - modifier = Modifier.padding(top = 16.dp) - ) - } - } -} - -@Composable -fun GeolocationPopup(inference: GeolocationInference) { - Surface( - modifier = Modifier - .fillMaxSize() - .background(Color.Black.copy(alpha = 0.6f)) - .clickable { }, - color = Color.Transparent - ) { - Box( - contentAlignment = Alignment.Center, - modifier = Modifier.fillMaxSize() - ) { - Surface( - shape = RoundedCornerShape(16.dp), - color = Color.White, - modifier = Modifier - .padding(16.dp) - .fillMaxWidth() - ) { - Column( - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Center, - modifier = Modifier.padding(16.dp) - ) { - Text( - text = "You are near ${inference.merchantName}", - fontWeight = FontWeight.Bold, - fontSize = 20.sp, - color = MaterialTheme.colorScheme.primary - ) - Spacer(modifier = Modifier.height(16.dp)) - Row( - horizontalArrangement = Arrangement.SpaceEvenly, - modifier = Modifier.fillMaxWidth() - ) { - Button(onClick = { /* TO DO: Handle Yes action */ }) { - Text("Yes") - } - Button(onClick = { /* TO DO: Handle No action */ }) { - Text("No") - } - } - } - } - } } } From 8b1507630e6645611a62e6eb286c259b07777872 Mon Sep 17 00:00:00 2001 From: Nandini Date: Tue, 23 Jul 2024 20:31:17 -0400 Subject: [PATCH 15/21] small UI change to popup --- .DS_Store | Bin 0 -> 8196 bytes .../purchaseBenefitsScreen/GeolocationPopup.kt | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..27c64bc4aada515d3d50b050d20ea6fc7e3b1f01 GIT binary patch literal 8196 zcmeHM&2G~`5S~p!<0$+D1X4I4S>jri5UNUuiwWhx6(cwR3UO_Uh3mCqha93vKEpfk z3S4;--h~rvwtKc9crlMs;@&BEJ6eIjyD7<*l)6NLM@tVzRI zE&>JONgf1=4AAPW`C5Zzz%pPNunbrRECYWB130r;oDJu`?zP%7U>W!?8Q}MWi^Av` zEH$cE2b4+yfGwDnpsqgtfi4?>p21QhED)hXfjU%}6hoNYLFjPwd&a-isKZI9nK6!; zS(pq(nAAhK%AJI#(Q3rHf3g&rcvi#3Mmc)56 z7<>_pX6xKm+i5#p=cWHf&i!Ii%<|D>`kY%&q)dVz^-1tFj^^Xu)dw;yCUF`~RX`j@ zaCz}8PD42#$yplaD%RH>PRHqtd;P^?xHs5#?+k~_ZFg~Zi2Cl{?sD02uHC$K@A3F; za+J#VdYi($D(Hf4AL|dOnccker)eV7Ls;1RJOwnPm=X$UhYo29W06>dJkx5~}d zW?ymRXTJXko3;I~aC*7Q4Oq>LS@$>Sr^1SqFBmQ#N#P?J+{tD)eu%apS zDc7Lxwdxp`)EI^0IR!7glZ|(^;=LNpPlSuY=ou_EvWe~L6b9P!p9!&I88|}>H1%5h zoc}-E{QLhI+L2wVWxz7 Date: Tue, 23 Jul 2024 20:34:01 -0400 Subject: [PATCH 16/21] updating gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 65a2682..ca1b2d1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +# macOS +.DS_Store + # Gradle files .gradle/ build/ From bcbc525f14426940693cc6b22190ac54622fdbd6 Mon Sep 17 00:00:00 2001 From: Nandini Date: Tue, 23 Jul 2024 20:52:02 -0400 Subject: [PATCH 17/21] allow user to choose location preference before calling location API --- app/build.gradle | 1 + .../purchaseBenefitsScreen/Purchase.kt | 27 ++++++++++++++++--- gradle/libs.versions.toml | 2 ++ 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index a7956bb..0fa5a49 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -92,6 +92,7 @@ dependencies { implementation libs.androidx.annotation implementation libs.android.libraries.places.places implementation libs.maps.android.places.places.ktx + implementation libs.accompanist.permissions // Kotlin Dependencies implementation platform(libs.jetbrains.kotlin.bom) diff --git a/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/Purchase.kt b/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/Purchase.kt index 899e501..1877e56 100644 --- a/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/Purchase.kt +++ b/app/src/main/java/edu/card/clarity/presentation/purchaseBenefitsScreen/Purchase.kt @@ -1,5 +1,6 @@ package edu.card.clarity.presentation.purchaseBenefitsScreen +import android.Manifest import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.clickable @@ -24,20 +25,38 @@ import androidx.compose.ui.unit.sp import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavController import androidx.navigation.compose.rememberNavController +import com.google.accompanist.permissions.ExperimentalPermissionsApi +import com.google.accompanist.permissions.rememberMultiplePermissionsState import edu.card.clarity.R import edu.card.clarity.enums.PurchaseType import edu.card.clarity.presentation.utils.Destinations +@OptIn(ExperimentalPermissionsApi::class) @Composable fun PurchaseScreen(navController: NavController, geolocationViewModel: GeolocationViewModel = hiltViewModel()) { - var showDialog by remember { mutableStateOf(true) } - val geolocationInference by geolocationViewModel.geolocationInference.collectAsState() + val locationPermissionsState = rememberMultiplePermissionsState( + permissions = listOf( + Manifest.permission.ACCESS_FINE_LOCATION, + Manifest.permission.ACCESS_COARSE_LOCATION + ) + ) LaunchedEffect(Unit) { - geolocationViewModel.fetchGeolocationInference() + locationPermissionsState.launchMultiplePermissionRequest() + } + + var showDialog by remember { mutableStateOf(false) } + val geolocationInference by geolocationViewModel.geolocationInference.collectAsState() + + // Wait for permissions to be granted before fetching inferences + LaunchedEffect(locationPermissionsState.allPermissionsGranted) { + if (locationPermissionsState.allPermissionsGranted) { + geolocationViewModel.fetchGeolocationInference() + showDialog = true + } } - if (showDialog) { + if (showDialog && locationPermissionsState.allPermissionsGranted) { GeolocationPopup( geolocationInference = geolocationInference?.firstOrNull(), onDismiss = { showDialog = false }, diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6b2fa77..0d2bc7f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,4 +1,5 @@ [versions] +accompanistPermissions = "0.31.1-alpha" agp = "8.5.1" coreTesting = "2.2.0" kotlin = "2.0.0" @@ -28,6 +29,7 @@ secrets = "2.0.1" [libraries] # Android +accompanist-permissions = { module = "com.google.accompanist:accompanist-permissions", version.ref = "accompanistPermissions" } androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } androidx-navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "navigationCompose" } androidx-ui-text-google-fonts = { module = "androidx.compose.ui:ui-text-google-fonts", version.ref = "uiTextGoogleFonts" } From d3fa9719ca999cbf571bf2e4934e5aa8ca64e36b Mon Sep 17 00:00:00 2001 From: Nandini Date: Tue, 23 Jul 2024 20:56:59 -0400 Subject: [PATCH 18/21] fixing merge conflicts --- .../edu/card/clarity/presentation/navigation/BottomNavGraph.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/edu/card/clarity/presentation/navigation/BottomNavGraph.kt b/app/src/main/java/edu/card/clarity/presentation/navigation/BottomNavGraph.kt index 47023ab..9ceac99 100644 --- a/app/src/main/java/edu/card/clarity/presentation/navigation/BottomNavGraph.kt +++ b/app/src/main/java/edu/card/clarity/presentation/navigation/BottomNavGraph.kt @@ -12,7 +12,6 @@ import edu.card.clarity.presentation.addCardScreen.AddCardScreen import edu.card.clarity.presentation.homeScreen.HomeScreen import edu.card.clarity.presentation.myCardScreen.MyCardsScreen import edu.card.clarity.presentation.purchaseBenefitsScreen.PurchaseScreen -import edu.card.clarity.presentation.UpcomingPaymentsScreen import edu.card.clarity.presentation.addBenefitScreen.AddBenefitScreen import edu.card.clarity.presentation.myBenefitsScreen.MyBenefitsScreen import edu.card.clarity.presentation.purchaseBenefitsScreen.PurchaseOptimalBenefitsScreen From 86c9a8a630c2a9df6b0eefce39841ecb6ddc4961 Mon Sep 17 00:00:00 2001 From: Lide Linus Zhang <39998175+LideLinusZhang@users.noreply.github.com> Date: Tue, 23 Jul 2024 22:29:42 -0400 Subject: [PATCH 19/21] Delete .DS_Store Signed-off-by: Lide Linus Zhang <39998175+LideLinusZhang@users.noreply.github.com> --- .DS_Store | Bin 8196 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 27c64bc4aada515d3d50b050d20ea6fc7e3b1f01..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8196 zcmeHM&2G~`5S~p!<0$+D1X4I4S>jri5UNUuiwWhx6(cwR3UO_Uh3mCqha93vKEpfk z3S4;--h~rvwtKc9crlMs;@&BEJ6eIjyD7<*l)6NLM@tVzRI zE&>JONgf1=4AAPW`C5Zzz%pPNunbrRECYWB130r;oDJu`?zP%7U>W!?8Q}MWi^Av` zEH$cE2b4+yfGwDnpsqgtfi4?>p21QhED)hXfjU%}6hoNYLFjPwd&a-isKZI9nK6!; zS(pq(nAAhK%AJI#(Q3rHf3g&rcvi#3Mmc)56 z7<>_pX6xKm+i5#p=cWHf&i!Ii%<|D>`kY%&q)dVz^-1tFj^^Xu)dw;yCUF`~RX`j@ zaCz}8PD42#$yplaD%RH>PRHqtd;P^?xHs5#?+k~_ZFg~Zi2Cl{?sD02uHC$K@A3F; za+J#VdYi($D(Hf4AL|dOnccker)eV7Ls;1RJOwnPm=X$UhYo29W06>dJkx5~}d zW?ymRXTJXko3;I~aC*7Q4Oq>LS@$>Sr^1SqFBmQ#N#P?J+{tD)eu%apS zDc7Lxwdxp`)EI^0IR!7glZ|(^;=LNpPlSuY=ou_EvWe~L6b9P!p9!&I88|}>H1%5h zoc}-E{QLhI+L2wVWxz7 Date: Tue, 23 Jul 2024 22:31:30 -0400 Subject: [PATCH 20/21] fix merge errors --- .../edu/card/clarity/presentation/navigation/BottomNavGraph.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/edu/card/clarity/presentation/navigation/BottomNavGraph.kt b/app/src/main/java/edu/card/clarity/presentation/navigation/BottomNavGraph.kt index f0603a5..601ce60 100644 --- a/app/src/main/java/edu/card/clarity/presentation/navigation/BottomNavGraph.kt +++ b/app/src/main/java/edu/card/clarity/presentation/navigation/BottomNavGraph.kt @@ -7,13 +7,13 @@ import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.navArgument import edu.card.clarity.enums.PurchaseType -import edu.card.clarity.presentation.MyReceiptsScreen import edu.card.clarity.presentation.addCardScreen.AddCardScreen import edu.card.clarity.presentation.addBenefitScreen.AddBenefitScreen import edu.card.clarity.presentation.upcomingPaymentsScreen.UpcomingPaymentsScreen import edu.card.clarity.presentation.homeScreen.HomeScreen import edu.card.clarity.presentation.myBenefitsScreen.MyBenefitsScreen import edu.card.clarity.presentation.myCardScreen.MyCardsScreen +import edu.card.clarity.presentation.myReceiptsScreen.MyReceiptsScreen import edu.card.clarity.presentation.purchaseBenefitsScreen.PurchaseOptimalBenefitsScreen import edu.card.clarity.presentation.purchaseBenefitsScreen.PurchaseScreen import edu.card.clarity.presentation.utils.ArgumentNames From 8cd1e6e6844d801d27529d4403f101b2b1967550 Mon Sep 17 00:00:00 2001 From: Linus Zhang Date: Tue, 23 Jul 2024 22:34:41 -0400 Subject: [PATCH 21/21] Merged upstream. --- .../java/edu/card/clarity/MainActivity.kt | 4 +- .../card/clarity/presentation/MainActivity.kt | 47 ------------------- .../clarity/{ => presentation}/MainScreen.kt | 2 +- .../presentation/navigation/BottomNavGraph.kt | 4 +- 4 files changed, 3 insertions(+), 54 deletions(-) delete mode 100644 app/src/main/java/edu/card/clarity/presentation/MainActivity.kt rename app/src/main/java/edu/card/clarity/{ => presentation}/MainScreen.kt (98%) diff --git a/app/src/main/java/edu/card/clarity/MainActivity.kt b/app/src/main/java/edu/card/clarity/MainActivity.kt index 83bfbbe..a6e6897 100644 --- a/app/src/main/java/edu/card/clarity/MainActivity.kt +++ b/app/src/main/java/edu/card/clarity/MainActivity.kt @@ -2,7 +2,6 @@ package edu.card.clarity import android.Manifest import android.content.pm.PackageManager -import android.os.Build import android.os.Bundle import android.util.Log import androidx.activity.ComponentActivity @@ -10,10 +9,9 @@ import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.contract.ActivityResultContracts -import androidx.activity.result.registerForActivityResult import androidx.core.app.ActivityCompat -import androidx.core.app.NotificationManagerCompat import dagger.hilt.android.AndroidEntryPoint +import edu.card.clarity.presentation.MainScreen import edu.card.clarity.ui.theme.CardClarityTheme @AndroidEntryPoint diff --git a/app/src/main/java/edu/card/clarity/presentation/MainActivity.kt b/app/src/main/java/edu/card/clarity/presentation/MainActivity.kt deleted file mode 100644 index 90c2582..0000000 --- a/app/src/main/java/edu/card/clarity/presentation/MainActivity.kt +++ /dev/null @@ -1,47 +0,0 @@ -package edu.card.clarity.presentation - -import android.os.Bundle -import androidx.activity.ComponentActivity -import androidx.activity.compose.setContent -import androidx.activity.enableEdgeToEdge -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.padding -import androidx.compose.material3.Scaffold -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.tooling.preview.Preview -import edu.card.clarity.ui.theme.CardClarityTheme - -class MainActivity : ComponentActivity() { - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - enableEdgeToEdge() - setContent { - CardClarityTheme { - Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding -> - Greeting( - name = "Android", - modifier = Modifier.padding(innerPadding) - ) - } - } - } - } -} - -@Composable -fun Greeting(name: String, modifier: Modifier = Modifier) { - Text( - text = "Hello $name!", - modifier = modifier - ) -} - -@Preview(showBackground = true) -@Composable -fun GreetingPreview() { - CardClarityTheme { - Greeting("Android") - } -} \ No newline at end of file diff --git a/app/src/main/java/edu/card/clarity/MainScreen.kt b/app/src/main/java/edu/card/clarity/presentation/MainScreen.kt similarity index 98% rename from app/src/main/java/edu/card/clarity/MainScreen.kt rename to app/src/main/java/edu/card/clarity/presentation/MainScreen.kt index e8f3072..246d3e5 100644 --- a/app/src/main/java/edu/card/clarity/MainScreen.kt +++ b/app/src/main/java/edu/card/clarity/presentation/MainScreen.kt @@ -1,4 +1,4 @@ -package edu.card.clarity +package edu.card.clarity.presentation import android.annotation.SuppressLint import androidx.compose.foundation.layout.RowScope diff --git a/app/src/main/java/edu/card/clarity/presentation/navigation/BottomNavGraph.kt b/app/src/main/java/edu/card/clarity/presentation/navigation/BottomNavGraph.kt index 063b717..35844a0 100644 --- a/app/src/main/java/edu/card/clarity/presentation/navigation/BottomNavGraph.kt +++ b/app/src/main/java/edu/card/clarity/presentation/navigation/BottomNavGraph.kt @@ -7,10 +7,8 @@ import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.navArgument import edu.card.clarity.enums.PurchaseType -import edu.card.clarity.presentation.MyReceiptsScreen import edu.card.clarity.presentation.addCardScreen.AddCardScreen import edu.card.clarity.presentation.addBenefitScreen.AddBenefitScreen -import edu.card.clarity.presentation.addCardScreen.AddCardScreen import edu.card.clarity.presentation.homeScreen.HomeScreen import edu.card.clarity.presentation.myBenefitsScreen.MyBenefitsScreen import edu.card.clarity.presentation.myCardScreen.MyCardsScreen @@ -37,7 +35,7 @@ fun BottomNavGraph(navController: NavHostController) { MyReceiptsScreen() } composable(Destinations.PURCHASE) { - PurchaseScreen() + PurchaseScreen(navController) } composable(Destinations.MY_CARDS) { MyCardsScreen(navController)