Skip to content

Commit d3abf2a

Browse files
committed
Add FruittieScreen + connect cart actions
1 parent b9635fb commit d3abf2a

File tree

9 files changed

+349
-67
lines changed

9 files changed

+349
-67
lines changed

Fruitties/androidApp/src/main/java/com/example/fruitties/android/MainActivity.kt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import androidx.navigation3.runtime.rememberSavedStateNavEntryDecorator
3434
import androidx.navigation3.ui.NavDisplay
3535
import androidx.navigation3.ui.rememberSceneSetupNavEntryDecorator
3636
import com.example.fruitties.android.ui.CartScreen
37+
import com.example.fruitties.android.ui.FruittieScreen
3738
import com.example.fruitties.android.ui.ListScreen
3839
import kotlinx.serialization.Serializable
3940

@@ -43,6 +44,9 @@ data object ListScreenKey : NavKey
4344
@Serializable
4445
data object CartScreenKey : NavKey
4546

47+
@Serializable
48+
data class FruittieScreenKey(val id: Long) : NavKey
49+
4650
class MainActivity : ComponentActivity() {
4751
override fun onCreate(savedInstanceState: Bundle?) {
4852
super.onCreate(savedInstanceState)
@@ -75,11 +79,23 @@ fun NavApp() {
7579
entryProvider = entryProvider {
7680
entry<ListScreenKey> {
7781
ListScreen(
82+
onFruittieClick = {
83+
backStack.add(FruittieScreenKey(it.id))
84+
},
7885
onClickViewCart = {
7986
backStack.add(CartScreenKey)
8087
},
8188
)
8289
}
90+
entry<FruittieScreenKey> {
91+
FruittieScreen(
92+
fruittieId = it.id,
93+
onNavBarBack = {
94+
backStack.removeIf { it is FruittieScreenKey }
95+
},
96+
)
97+
}
98+
8399
entry<CartScreenKey> {
84100
CartScreen(
85101
onNavBarBack = {
@@ -90,3 +106,4 @@ fun NavApp() {
90106
},
91107
)
92108
}
109+

Fruitties/androidApp/src/main/java/com/example/fruitties/android/ui/CartScreen.kt

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package com.example.fruitties.android.ui
1818

1919
import androidx.compose.foundation.layout.Column
20+
import androidx.compose.foundation.layout.Row
2021
import androidx.compose.foundation.layout.Spacer
2122
import androidx.compose.foundation.layout.WindowInsets
2223
import androidx.compose.foundation.layout.WindowInsetsSides
@@ -25,15 +26,20 @@ import androidx.compose.foundation.layout.only
2526
import androidx.compose.foundation.layout.padding
2627
import androidx.compose.foundation.layout.safeDrawing
2728
import androidx.compose.foundation.layout.systemBars
29+
import androidx.compose.foundation.layout.width
2830
import androidx.compose.foundation.layout.windowInsetsBottomHeight
2931
import androidx.compose.foundation.lazy.LazyColumn
3032
import androidx.compose.foundation.lazy.items
3133
import androidx.compose.material.icons.Icons
3234
import androidx.compose.material.icons.automirrored.filled.ArrowBack
3335
import androidx.compose.material3.CenterAlignedTopAppBar
3436
import androidx.compose.material3.ExperimentalMaterial3Api
37+
import androidx.compose.material3.FilledIconButton
38+
import androidx.compose.material3.HorizontalDivider
3539
import androidx.compose.material3.Icon
3640
import androidx.compose.material3.IconButton
41+
import androidx.compose.material3.IconButtonColors
42+
import androidx.compose.material3.IconButtonDefaults
3743
import androidx.compose.material3.MaterialTheme
3844
import androidx.compose.material3.Scaffold
3945
import androidx.compose.material3.Text
@@ -43,12 +49,15 @@ import androidx.compose.runtime.collectAsState
4349
import androidx.compose.runtime.getValue
4450
import androidx.compose.ui.Alignment
4551
import androidx.compose.ui.Modifier
52+
import androidx.compose.ui.graphics.Color
4653
import androidx.compose.ui.platform.LocalContext
4754
import androidx.compose.ui.res.stringResource
55+
import androidx.compose.ui.text.style.TextAlign
4856
import androidx.compose.ui.unit.dp
4957
import androidx.lifecycle.viewmodel.compose.viewModel
5058
import com.example.fruitties.android.R
5159
import com.example.fruitties.android.di.App
60+
import com.example.fruitties.model.CartItemDetails
5261
import com.example.fruitties.viewmodel.CartViewModel
5362
import com.example.fruitties.viewmodel.creationExtras
5463

@@ -81,7 +90,7 @@ fun CartScreen(onNavBarBack: () -> Unit) {
8190
}
8291
},
8392
title = {
84-
Text(text = stringResource(R.string.frutties))
93+
Text(text = stringResource(R.string.cart))
8594
},
8695
colors = TopAppBarDefaults.topAppBarColors(
8796
containerColor = MaterialTheme.colorScheme.primary,
@@ -108,14 +117,17 @@ fun CartScreen(onNavBarBack: () -> Unit) {
108117
val cartItemCount = cartState.totalItemCount
109118
Text(
110119
text = "Cart has $cartItemCount items",
111-
modifier = Modifier.padding(8.dp),
112120
)
121+
HorizontalDivider()
113122
LazyColumn(
114123
modifier = Modifier.fillMaxWidth(),
115-
horizontalAlignment = Alignment.CenterHorizontally,
116124
) {
117125
items(cartState.cartDetails) { cartItem ->
118-
Text(text = "${cartItem.fruittie.name}: ${cartItem.count}")
126+
CartItem(
127+
cartItem = cartItem,
128+
decreaseCountClick = viewModel::decreaseCountClick,
129+
increaseCountClick = viewModel::increaseCountClick,
130+
)
119131
}
120132
item {
121133
Spacer(
@@ -128,3 +140,39 @@ fun CartScreen(onNavBarBack: () -> Unit) {
128140
}
129141
}
130142
}
143+
144+
@Composable
145+
fun CartItem(
146+
cartItem: CartItemDetails,
147+
increaseCountClick: (CartItemDetails) -> Unit,
148+
decreaseCountClick: (CartItemDetails) -> Unit,
149+
) {
150+
Row(
151+
verticalAlignment = Alignment.CenterVertically,
152+
) {
153+
Text(text = "${cartItem.count}x")
154+
Spacer(Modifier.width(8.dp))
155+
Text(text = cartItem.fruittie.name)
156+
Spacer(Modifier.weight(1f))
157+
FilledIconButton(
158+
onClick = { decreaseCountClick(cartItem) },
159+
colors = IconButtonDefaults.filledIconButtonColors(containerColor = Color.Red),
160+
) {
161+
Text(
162+
text = "-",
163+
color = MaterialTheme.colorScheme.onPrimary,
164+
textAlign = TextAlign.Center,
165+
)
166+
}
167+
FilledIconButton(
168+
onClick = { increaseCountClick(cartItem) },
169+
colors = IconButtonDefaults.filledIconButtonColors(containerColor = Color.Green),
170+
) {
171+
Text(
172+
text = "+",
173+
color = MaterialTheme.colorScheme.onPrimary,
174+
textAlign = TextAlign.Center,
175+
)
176+
}
177+
}
178+
}
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
package com.example.fruitties.android.ui
2+
3+
import androidx.compose.foundation.layout.Column
4+
import androidx.compose.foundation.layout.Row
5+
import androidx.compose.foundation.layout.Spacer
6+
import androidx.compose.foundation.layout.fillMaxSize
7+
import androidx.compose.foundation.layout.padding
8+
import androidx.compose.foundation.layout.width
9+
import androidx.compose.material.icons.Icons
10+
import androidx.compose.material.icons.automirrored.filled.ArrowBack
11+
import androidx.compose.material.icons.filled.ShoppingCart
12+
import androidx.compose.material3.CircularProgressIndicator
13+
import androidx.compose.material3.ExperimentalMaterial3Api
14+
import androidx.compose.material3.FloatingActionButton
15+
import androidx.compose.material3.Icon
16+
import androidx.compose.material3.IconButton
17+
import androidx.compose.material3.MaterialTheme
18+
import androidx.compose.material3.Scaffold
19+
import androidx.compose.material3.Text
20+
import androidx.compose.material3.TopAppBar
21+
import androidx.compose.runtime.Composable
22+
import androidx.compose.runtime.collectAsState
23+
import androidx.compose.ui.Alignment
24+
import androidx.compose.ui.Modifier
25+
import androidx.compose.ui.platform.LocalContext
26+
import androidx.compose.ui.res.stringResource
27+
import androidx.compose.ui.unit.dp
28+
import androidx.lifecycle.viewmodel.compose.viewModel
29+
import com.example.fruitties.android.R
30+
import com.example.fruitties.android.di.App
31+
import com.example.fruitties.model.Fruittie
32+
import com.example.fruitties.viewmodel.FruittieViewModel
33+
import com.example.fruitties.viewmodel.FruittieViewModel.Companion.FRUITTIE_ID_KEY
34+
import com.example.fruitties.viewmodel.creationExtras
35+
36+
@OptIn(ExperimentalMaterial3Api::class)
37+
@Composable
38+
fun FruittieScreen(
39+
fruittieId: Long,
40+
onNavBarBack: () -> Unit
41+
) {
42+
val app = LocalContext.current.applicationContext as App
43+
44+
val viewModel: FruittieViewModel = viewModel(
45+
factory = FruittieViewModel.Factory,
46+
extras = creationExtras(app.container) {
47+
set(FRUITTIE_ID_KEY, fruittieId)
48+
},
49+
)
50+
51+
val state = viewModel.state.collectAsState().value
52+
53+
FruittieScreen(
54+
state = state,
55+
onNavBarBack = onNavBarBack,
56+
addToCart = { viewModel.addToCard(it) }
57+
)
58+
}
59+
60+
@OptIn(ExperimentalMaterial3Api::class)
61+
@Composable
62+
fun FruittieScreen(
63+
state: FruittieViewModel.State,
64+
addToCart: (Fruittie) -> Unit,
65+
onNavBarBack: () -> Unit
66+
) {
67+
Scaffold(
68+
topBar = {
69+
TopAppBar(
70+
title = {
71+
Text(
72+
(state as? FruittieViewModel.State.Content)?.fruittie?.name
73+
?: stringResource(R.string.loading)
74+
)
75+
},
76+
actions = {
77+
val inCart = (state as? FruittieViewModel.State.Content)?.inCart ?: 0
78+
Text(stringResource(R.string.in_cart, inCart))
79+
Spacer(Modifier.width(8.dp))
80+
},
81+
navigationIcon = {
82+
IconButton(onClick = onNavBarBack) {
83+
Icon(
84+
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
85+
contentDescription = stringResource(R.string.navigate_back),
86+
)
87+
}
88+
},
89+
)
90+
},
91+
floatingActionButton = {
92+
// Check if state is loaded
93+
if (state !is FruittieViewModel.State.Content) return@Scaffold
94+
95+
FloatingActionButton(
96+
shape = MaterialTheme.shapes.extraLarge,
97+
onClick = { addToCart(state.fruittie) }
98+
) {
99+
Row(
100+
modifier = Modifier.padding(
101+
horizontal = 16.dp
102+
),
103+
verticalAlignment = Alignment.CenterVertically
104+
) {
105+
Icon(
106+
Icons.Filled.ShoppingCart,
107+
contentDescription = null
108+
)
109+
Spacer(Modifier.width(8.dp))
110+
Text(text = stringResource(R.string.add_to_cart))
111+
}
112+
}
113+
}
114+
) {
115+
Column(
116+
horizontalAlignment = Alignment.CenterHorizontally,
117+
modifier = Modifier
118+
.padding(it)
119+
.fillMaxSize()
120+
) {
121+
when (state) {
122+
FruittieViewModel.State.Loading -> CircularProgressIndicator()
123+
is FruittieViewModel.State.Content -> {
124+
Text(state.fruittie.fullName)
125+
Text(state.fruittie.calories)
126+
}
127+
}
128+
}
129+
}
130+
}

0 commit comments

Comments
 (0)