Skip to content

Commit 8050cdb

Browse files
authored
Merge branch 'main' into renovate/kotlin-dependencies
2 parents 88539c7 + 0392633 commit 8050cdb

File tree

27 files changed

+958
-341
lines changed

27 files changed

+958
-341
lines changed

.github/workflows/Fruitties.yaml

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,36 +6,57 @@ on:
66
branches:
77
- main
88
- feature/*
9-
pull_request:
9+
paths:
10+
- 'Fruitties/**'
11+
- '.github/workflows/Fruitties.yml'
12+
pull_request:
13+
paths:
14+
- 'Fruitties/**'
15+
- '.github/workflows/Fruitties.yml'
1016

1117
concurrency:
1218
group: build-${{ github.ref }}
1319
cancel-in-progress: true
1420

21+
env:
22+
SAMPLE_PATH: Fruitties
23+
1524
jobs:
1625
build_android:
1726
name: Build Android app
1827
runs-on: ubuntu-latest
28+
defaults:
29+
run:
30+
working-directory: ${{ env.SAMPLE_PATH }}
31+
1932
steps:
2033
- name: Checkout
2134
uses: actions/checkout@v4
2235

23-
- name: Validate Gradle Wrapper
24-
uses: gradle/actions/wrapper-validation@v3
25-
2636
- name: Set up JDK 17
2737
uses: actions/setup-java@v4
2838
with:
2939
distribution: 'zulu'
3040
java-version: 17
3141

42+
- name: Setup Gradle
43+
uses: gradle/actions/setup-gradle@v4
44+
with:
45+
cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }}
46+
47+
- name: Run Spotless check
48+
run: ./gradlew spotlessCheck --stacktrace
49+
3250
- name: Build app
33-
working-directory: ./Fruitties
34-
run: ./gradlew assemble --stacktrace
51+
run: ./gradlew assembleDebug lintDebug --stacktrace
3552

3653
build_ios:
3754
name: Build iOS app
3855
runs-on: macos-latest
56+
defaults:
57+
run:
58+
working-directory: ${{ env.SAMPLE_PATH }}
59+
3960
steps:
4061
- uses: maxim-lobanov/setup-xcode@v1
4162
with:
@@ -44,15 +65,11 @@ jobs:
4465
- name: Checkout
4566
uses: actions/checkout@v4
4667

47-
- name: Validate Gradle Wrapper
48-
uses: gradle/wrapper-validation-action@v3
49-
50-
- name: Set up JDK 17
51-
uses: actions/setup-java@v4
68+
- name: Build iOS app
69+
uses: mxcl/xcodebuild@v3
5270
with:
53-
distribution: 'zulu'
54-
java-version: 17
55-
56-
- name: Build app
57-
working-directory: ./Fruitties
58-
run: xcodebuild -project iosApp/iosApp.xcodeproj -configuration Debug -scheme iosApp -sdk iphonesimulator
71+
xcode: ^16
72+
scheme: iosApp
73+
platform: iOS
74+
action: build
75+
working-directory: ${{ env.SAMPLE_PATH }}/iosApp

Fruitties/androidApp/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ dependencies {
7676
implementation(libs.compose.ui)
7777
implementation(libs.compose.ui.tooling.preview)
7878
implementation(libs.compose.material3)
79+
implementation(libs.androidx.material.icons.core)
7980
implementation(libs.androidx.activity.compose)
8081
implementation(libs.androidx.paging.compose.android)
8182
implementation(libs.androidx.lifecycle.viewmodel.compose)

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

Lines changed: 18 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,11 @@ data object ListScreenKey : NavKey
4344
@Serializable
4445
data object CartScreenKey : NavKey
4546

47+
@Serializable
48+
data class FruittieScreenKey(
49+
val id: Long,
50+
) : NavKey
51+
4652
class MainActivity : ComponentActivity() {
4753
override fun onCreate(savedInstanceState: Bundle?) {
4854
super.onCreate(savedInstanceState)
@@ -75,11 +81,23 @@ fun NavApp() {
7581
entryProvider = entryProvider {
7682
entry<ListScreenKey> {
7783
ListScreen(
84+
onFruittieClick = {
85+
backStack.add(FruittieScreenKey(it.id))
86+
},
7887
onClickViewCart = {
7988
backStack.add(CartScreenKey)
8089
},
8190
)
8291
}
92+
entry<FruittieScreenKey> {
93+
FruittieScreen(
94+
fruittieId = it.id,
95+
onNavBarBack = {
96+
backStack.removeIf { it is FruittieScreenKey }
97+
},
98+
)
99+
}
100+
83101
entry<CartScreenKey> {
84102
CartScreen(
85103
onNavBarBack = {

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

Lines changed: 138 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,42 +17,54 @@
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
24+
import androidx.compose.foundation.layout.consumeWindowInsets
2325
import androidx.compose.foundation.layout.fillMaxWidth
2426
import androidx.compose.foundation.layout.only
2527
import androidx.compose.foundation.layout.padding
2628
import androidx.compose.foundation.layout.safeDrawing
2729
import androidx.compose.foundation.layout.systemBars
30+
import androidx.compose.foundation.layout.width
2831
import androidx.compose.foundation.layout.windowInsetsBottomHeight
2932
import androidx.compose.foundation.lazy.LazyColumn
3033
import androidx.compose.foundation.lazy.items
3134
import androidx.compose.material.icons.Icons
3235
import androidx.compose.material.icons.automirrored.filled.ArrowBack
3336
import androidx.compose.material3.CenterAlignedTopAppBar
3437
import androidx.compose.material3.ExperimentalMaterial3Api
38+
import androidx.compose.material3.FilledIconButton
39+
import androidx.compose.material3.HorizontalDivider
3540
import androidx.compose.material3.Icon
3641
import androidx.compose.material3.IconButton
42+
import androidx.compose.material3.IconButtonDefaults
3743
import androidx.compose.material3.MaterialTheme
3844
import androidx.compose.material3.Scaffold
3945
import androidx.compose.material3.Text
4046
import androidx.compose.material3.TopAppBarDefaults
4147
import androidx.compose.runtime.Composable
4248
import androidx.compose.runtime.collectAsState
4349
import androidx.compose.runtime.getValue
44-
import androidx.compose.runtime.remember
4550
import androidx.compose.ui.Alignment
4651
import androidx.compose.ui.Modifier
52+
import androidx.compose.ui.graphics.Color
4753
import androidx.compose.ui.platform.LocalContext
4854
import androidx.compose.ui.res.stringResource
55+
import androidx.compose.ui.text.style.TextAlign
56+
import androidx.compose.ui.tooling.preview.Preview
4957
import androidx.compose.ui.unit.dp
5058
import androidx.lifecycle.viewmodel.compose.viewModel
59+
import com.example.fruitties.android.MyApplicationTheme
5160
import com.example.fruitties.android.R
5261
import com.example.fruitties.android.di.App
62+
import com.example.fruitties.model.CartItemDetails
63+
import com.example.fruitties.model.Fruittie
64+
import com.example.fruitties.viewmodel.CartUiState
5365
import com.example.fruitties.viewmodel.CartViewModel
66+
import com.example.fruitties.viewmodel.creationExtras
5467

55-
@OptIn(ExperimentalMaterial3Api::class)
5668
@Composable
5769
fun CartScreen(onNavBarBack: () -> Unit) {
5870
// Instantiate a ViewModel with a dependency on the AppContainer.
@@ -61,17 +73,30 @@ fun CartScreen(onNavBarBack: () -> Unit) {
6173
// Here we put the KMP-compatible AppContainer into the extras
6274
// so it can be passed to the ViewModel factory.
6375
val app = LocalContext.current.applicationContext as App
64-
val extras = remember(app) {
65-
val container = app.container
66-
CartViewModel.creationExtras(container)
67-
}
76+
6877
val viewModel: CartViewModel = viewModel(
6978
factory = CartViewModel.Factory,
70-
extras = extras,
79+
extras = creationExtras(app.container),
7180
)
7281

7382
val cartState by viewModel.cartUiState.collectAsState()
7483

84+
CartScreen(
85+
onNavBarBack = onNavBarBack,
86+
cartState = cartState,
87+
increaseCountClick = viewModel::increaseCountClick,
88+
decreaseCountClick = viewModel::decreaseCountClick,
89+
)
90+
}
91+
92+
@OptIn(ExperimentalMaterial3Api::class)
93+
@Composable
94+
fun CartScreen(
95+
onNavBarBack: () -> Unit,
96+
cartState: CartUiState,
97+
decreaseCountClick: (CartItemDetails) -> Unit,
98+
increaseCountClick: (CartItemDetails) -> Unit,
99+
) {
75100
Scaffold(
76101
topBar = {
77102
CenterAlignedTopAppBar(
@@ -84,7 +109,7 @@ fun CartScreen(onNavBarBack: () -> Unit) {
84109
}
85110
},
86111
title = {
87-
Text(text = stringResource(R.string.frutties))
112+
Text(text = stringResource(R.string.cart))
88113
},
89114
colors = TopAppBarDefaults.topAppBarColors(
90115
containerColor = MaterialTheme.colorScheme.primary,
@@ -103,22 +128,24 @@ fun CartScreen(onNavBarBack: () -> Unit) {
103128
) { paddingValues ->
104129
Column(
105130
modifier = Modifier
106-
// Support edge-to-edge (required on Android 15)
107-
// https://developer.android.com/develop/ui/compose/layouts/insets#inset-size
108131
.padding(paddingValues)
132+
.consumeWindowInsets(paddingValues)
109133
.padding(16.dp),
110134
) {
111135
val cartItemCount = cartState.totalItemCount
112136
Text(
113-
text = "Cart has $cartItemCount items",
114-
modifier = Modifier.padding(8.dp),
137+
text = stringResource(R.string.cart_has_items, cartItemCount),
115138
)
139+
HorizontalDivider()
116140
LazyColumn(
117141
modifier = Modifier.fillMaxWidth(),
118-
horizontalAlignment = Alignment.CenterHorizontally,
119142
) {
120143
items(cartState.cartDetails) { cartItem ->
121-
Text(text = "${cartItem.fruittie.name}: ${cartItem.count}")
144+
CartItem(
145+
cartItem = cartItem,
146+
decreaseCountClick = decreaseCountClick,
147+
increaseCountClick = increaseCountClick,
148+
)
122149
}
123150
item {
124151
Spacer(
@@ -131,3 +158,100 @@ fun CartScreen(onNavBarBack: () -> Unit) {
131158
}
132159
}
133160
}
161+
162+
@Composable
163+
fun CartItem(
164+
cartItem: CartItemDetails,
165+
increaseCountClick: (CartItemDetails) -> Unit,
166+
decreaseCountClick: (CartItemDetails) -> Unit,
167+
modifier: Modifier = Modifier,
168+
) {
169+
Row(
170+
modifier = modifier,
171+
verticalAlignment = Alignment.CenterVertically,
172+
) {
173+
Text(text = "${cartItem.count}x")
174+
Spacer(Modifier.width(8.dp))
175+
Text(text = cartItem.fruittie.name)
176+
Spacer(Modifier.weight(1f))
177+
FilledIconButton(
178+
onClick = { decreaseCountClick(cartItem) },
179+
colors = IconButtonDefaults.filledIconButtonColors(containerColor = MaterialTheme.colorScheme.error),
180+
) {
181+
Text(
182+
text = "-",
183+
color = MaterialTheme.colorScheme.onPrimary,
184+
textAlign = TextAlign.Center,
185+
)
186+
}
187+
FilledIconButton(
188+
onClick = { increaseCountClick(cartItem) },
189+
colors = IconButtonDefaults.filledIconButtonColors(containerColor = Color.Green),
190+
) {
191+
Text(
192+
text = "+",
193+
color = MaterialTheme.colorScheme.onPrimary,
194+
textAlign = TextAlign.Center,
195+
)
196+
}
197+
}
198+
}
199+
200+
@Preview
201+
@Composable
202+
private fun CartScreenPreview() {
203+
MyApplicationTheme {
204+
CartScreen(
205+
onNavBarBack = {},
206+
cartState = CartUiState(
207+
cartDetails = listOf(
208+
CartItemDetails(
209+
fruittie = Fruittie(
210+
name = "Banana",
211+
fullName = "Banana Banana",
212+
calories = "100",
213+
),
214+
count = 4,
215+
),
216+
CartItemDetails(
217+
fruittie = Fruittie(
218+
name = "Orange",
219+
fullName = "Orange Orange",
220+
calories = "100",
221+
),
222+
count = 1,
223+
),
224+
CartItemDetails(
225+
fruittie = Fruittie(
226+
name = "Apple",
227+
fullName = "Apple Apple",
228+
calories = "100",
229+
),
230+
count = 100,
231+
),
232+
),
233+
),
234+
decreaseCountClick = {},
235+
increaseCountClick = {},
236+
)
237+
}
238+
}
239+
240+
@Preview
241+
@Composable
242+
private fun CartItemPreview() {
243+
MyApplicationTheme {
244+
CartItem(
245+
cartItem = CartItemDetails(
246+
fruittie = Fruittie(
247+
name = "Banana",
248+
fullName = "Banana Banana",
249+
calories = "100",
250+
),
251+
count = 4,
252+
),
253+
increaseCountClick = {},
254+
decreaseCountClick = {},
255+
)
256+
}
257+
}

0 commit comments

Comments
 (0)