Compare commits
10 Commits
14f13dd912
...
d54998cf29
| Author | SHA1 | Date | |
|---|---|---|---|
| d54998cf29 | |||
| 27be844ddb | |||
| 6dd65a9a9e | |||
|
|
82b7dc7723 | ||
|
|
8b50e72975 | ||
|
|
7097a75f37 | ||
|
|
a5118e6dfe | ||
|
|
8f9aedaebc | ||
|
|
5b8dab87ee | ||
|
|
1c31d367a1 |
6
.github/renovate.json
vendored
Normal file
6
.github/renovate.json
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||||
|
"extends": [
|
||||||
|
"local>android/.github:renovate-config"
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -5,15 +5,12 @@ This app contains an order flow for cupcakes with options for quantity, flavor,
|
|||||||
The order details get displayed on an order summary screen and can be shared to another app to
|
The order details get displayed on an order summary screen and can be shared to another app to
|
||||||
send the order.
|
send the order.
|
||||||
|
|
||||||
TODO
|
|
||||||
|
|
||||||
|
|
||||||
Pre-requisites
|
Pre-requisites
|
||||||
--------------
|
--------------
|
||||||
* Experience with Kotlin syntax.
|
* Experience with Kotlin syntax.
|
||||||
* How to create and run a project in Android Studio.
|
* How to create and run a project in Android Studio.
|
||||||
* How to create composable functions
|
* How to create composable functions
|
||||||
* TODO
|
|
||||||
|
|
||||||
|
|
||||||
Getting Started
|
Getting Started
|
||||||
|
|||||||
@ -21,6 +21,8 @@ import androidx.annotation.StringRes
|
|||||||
import androidx.compose.foundation.layout.fillMaxHeight
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.ArrowBack
|
import androidx.compose.material.icons.filled.ArrowBack
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
@ -115,7 +117,10 @@ fun CupcakeApp(
|
|||||||
NavHost(
|
NavHost(
|
||||||
navController = navController,
|
navController = navController,
|
||||||
startDestination = CupcakeScreen.Start.name,
|
startDestination = CupcakeScreen.Start.name,
|
||||||
modifier = Modifier.padding(innerPadding)
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
|
.padding(innerPadding)
|
||||||
) {
|
) {
|
||||||
composable(route = CupcakeScreen.Start.name) {
|
composable(route = CupcakeScreen.Start.name) {
|
||||||
StartOrderScreen(
|
StartOrderScreen(
|
||||||
|
|||||||
@ -18,13 +18,13 @@ package com.example.cupcake
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
import androidx.core.view.WindowCompat
|
import androidx.activity.enableEdgeToEdge
|
||||||
import com.example.cupcake.ui.theme.CupcakeTheme
|
import com.example.cupcake.ui.theme.CupcakeTheme
|
||||||
|
|
||||||
class MainActivity : ComponentActivity() {
|
class MainActivity : ComponentActivity() {
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
enableEdgeToEdge()
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
WindowCompat.setDecorFitsSystemWindows(window, false)
|
|
||||||
setContent {
|
setContent {
|
||||||
CupcakeTheme {
|
CupcakeTheme {
|
||||||
CupcakeApp()
|
CupcakeApp()
|
||||||
|
|||||||
@ -39,6 +39,7 @@ import androidx.compose.ui.res.stringResource
|
|||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import com.example.cupcake.R
|
import com.example.cupcake.R
|
||||||
import com.example.cupcake.ui.components.FormattedPriceLabel
|
import com.example.cupcake.ui.components.FormattedPriceLabel
|
||||||
|
import com.example.cupcake.ui.theme.CupcakeTheme
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Composable that displays the list of items as [RadioButton] options,
|
* Composable that displays the list of items as [RadioButton] options,
|
||||||
@ -54,14 +55,14 @@ fun SelectOptionScreen(
|
|||||||
onCancelButtonClicked: () -> Unit = {},
|
onCancelButtonClicked: () -> Unit = {},
|
||||||
onNextButtonClicked: () -> Unit = {},
|
onNextButtonClicked: () -> Unit = {},
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
){
|
) {
|
||||||
var selectedValue by rememberSaveable { mutableStateOf("") }
|
var selectedValue by rememberSaveable { mutableStateOf("") }
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
verticalArrangement = Arrangement.SpaceBetween
|
verticalArrangement = Arrangement.SpaceBetween
|
||||||
) {
|
) {
|
||||||
Column(modifier = Modifier.padding(dimensionResource(R.dimen.padding_medium))){
|
Column(modifier = Modifier.padding(dimensionResource(R.dimen.padding_medium))) {
|
||||||
options.forEach { item ->
|
options.forEach { item ->
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.selectable(
|
modifier = Modifier.selectable(
|
||||||
@ -72,7 +73,7 @@ fun SelectOptionScreen(
|
|||||||
}
|
}
|
||||||
),
|
),
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
){
|
) {
|
||||||
RadioButton(
|
RadioButton(
|
||||||
selected = selectedValue == item,
|
selected = selectedValue == item,
|
||||||
onClick = {
|
onClick = {
|
||||||
@ -100,12 +101,14 @@ fun SelectOptionScreen(
|
|||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(dimensionResource(R.dimen.padding_medium))
|
.padding(dimensionResource(R.dimen.padding_medium)),
|
||||||
.weight(1f, false),
|
|
||||||
horizontalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.padding_medium)),
|
horizontalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.padding_medium)),
|
||||||
verticalAlignment = Alignment.Bottom
|
verticalAlignment = Alignment.Bottom
|
||||||
){
|
) {
|
||||||
OutlinedButton(modifier = Modifier.weight(1f), onClick = onCancelButtonClicked) {
|
OutlinedButton(
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
onClick = onCancelButtonClicked
|
||||||
|
) {
|
||||||
Text(stringResource(R.string.cancel))
|
Text(stringResource(R.string.cancel))
|
||||||
}
|
}
|
||||||
Button(
|
Button(
|
||||||
@ -123,10 +126,12 @@ fun SelectOptionScreen(
|
|||||||
|
|
||||||
@Preview
|
@Preview
|
||||||
@Composable
|
@Composable
|
||||||
fun SelectOptionPreview(){
|
fun SelectOptionPreview() {
|
||||||
SelectOptionScreen(
|
CupcakeTheme {
|
||||||
subtotal = "299.99",
|
SelectOptionScreen(
|
||||||
options = listOf("Option 1", "Option 2", "Option 3", "Option 4"),
|
subtotal = "299.99",
|
||||||
modifier = Modifier.fillMaxHeight()
|
options = listOf("Option 1", "Option 2", "Option 3", "Option 4"),
|
||||||
)
|
modifier = Modifier.fillMaxHeight()
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,9 +19,7 @@ import androidx.annotation.StringRes
|
|||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxHeight
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
@ -41,6 +39,7 @@ import androidx.compose.ui.tooling.preview.Preview
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.example.cupcake.R
|
import com.example.cupcake.R
|
||||||
import com.example.cupcake.data.DataSource
|
import com.example.cupcake.data.DataSource
|
||||||
|
import com.example.cupcake.ui.theme.CupcakeTheme
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Composable that allows the user to select the desired cupcake quantity and expects
|
* Composable that allows the user to select the desired cupcake quantity and expects
|
||||||
@ -52,7 +51,7 @@ fun StartOrderScreen(
|
|||||||
quantityOptions: List<Pair<Int, Int>>,
|
quantityOptions: List<Pair<Int, Int>>,
|
||||||
onNextButtonClicked: (Int) -> Unit,
|
onNextButtonClicked: (Int) -> Unit,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
){
|
) {
|
||||||
Column(
|
Column(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
verticalArrangement = Arrangement.SpaceBetween
|
verticalArrangement = Arrangement.SpaceBetween
|
||||||
@ -75,20 +74,19 @@ fun StartOrderScreen(
|
|||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.height(dimensionResource(R.dimen.padding_small)))
|
Spacer(modifier = Modifier.height(dimensionResource(R.dimen.padding_small)))
|
||||||
}
|
}
|
||||||
Row(modifier = Modifier.weight(1f, false)) {
|
Column(
|
||||||
Column(
|
modifier = Modifier.fillMaxWidth(),
|
||||||
modifier = Modifier.fillMaxWidth(),
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
verticalArrangement = Arrangement.spacedBy(
|
||||||
verticalArrangement = Arrangement.spacedBy(
|
dimensionResource(id = R.dimen.padding_medium)
|
||||||
dimensionResource(id = R.dimen.padding_medium)
|
)
|
||||||
|
) {
|
||||||
|
quantityOptions.forEach { item ->
|
||||||
|
SelectQuantityButton(
|
||||||
|
labelResourceId = item.first,
|
||||||
|
onClick = { onNextButtonClicked(item.second) },
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
)
|
)
|
||||||
) {
|
|
||||||
quantityOptions.forEach { item ->
|
|
||||||
SelectQuantityButton(
|
|
||||||
labelResourceId = item.first,
|
|
||||||
onClick = { onNextButtonClicked(item.second) }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -103,7 +101,7 @@ fun SelectQuantityButton(
|
|||||||
@StringRes labelResourceId: Int,
|
@StringRes labelResourceId: Int,
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
){
|
) {
|
||||||
Button(
|
Button(
|
||||||
onClick = onClick,
|
onClick = onClick,
|
||||||
modifier = modifier.widthIn(min = 250.dp)
|
modifier = modifier.widthIn(min = 250.dp)
|
||||||
@ -114,10 +112,14 @@ fun SelectQuantityButton(
|
|||||||
|
|
||||||
@Preview
|
@Preview
|
||||||
@Composable
|
@Composable
|
||||||
fun StartOrderPreview(){
|
fun StartOrderPreview() {
|
||||||
StartOrderScreen(
|
CupcakeTheme {
|
||||||
quantityOptions = DataSource.quantityOptions,
|
StartOrderScreen(
|
||||||
onNextButtonClicked = {},
|
quantityOptions = DataSource.quantityOptions,
|
||||||
modifier = Modifier.fillMaxSize().padding(dimensionResource(R.dimen.padding_medium))
|
onNextButtonClicked = {},
|
||||||
)
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(dimensionResource(R.dimen.padding_medium))
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -38,6 +38,7 @@ import androidx.compose.ui.tooling.preview.Preview
|
|||||||
import com.example.cupcake.R
|
import com.example.cupcake.R
|
||||||
import com.example.cupcake.data.OrderUiState
|
import com.example.cupcake.data.OrderUiState
|
||||||
import com.example.cupcake.ui.components.FormattedPriceLabel
|
import com.example.cupcake.ui.components.FormattedPriceLabel
|
||||||
|
import com.example.cupcake.ui.theme.CupcakeTheme
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This composable expects [orderUiState] that represents the order state, [onCancelButtonClicked]
|
* This composable expects [orderUiState] that represents the order state, [onCancelButtonClicked]
|
||||||
@ -50,7 +51,7 @@ fun OrderSummaryScreen(
|
|||||||
onCancelButtonClicked: () -> Unit,
|
onCancelButtonClicked: () -> Unit,
|
||||||
onSendButtonClicked: (String, String) -> Unit,
|
onSendButtonClicked: (String, String) -> Unit,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
){
|
) {
|
||||||
val resources = LocalContext.current.resources
|
val resources = LocalContext.current.resources
|
||||||
|
|
||||||
val numberOfCupcakes = resources.getQuantityString(
|
val numberOfCupcakes = resources.getQuantityString(
|
||||||
@ -97,9 +98,7 @@ fun OrderSummaryScreen(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier.padding(dimensionResource(R.dimen.padding_medium))
|
||||||
.weight(1f, false)
|
|
||||||
.padding(dimensionResource(R.dimen.padding_medium))
|
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.padding_small))
|
verticalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.padding_small))
|
||||||
@ -123,11 +122,13 @@ fun OrderSummaryScreen(
|
|||||||
|
|
||||||
@Preview
|
@Preview
|
||||||
@Composable
|
@Composable
|
||||||
fun OrderSummaryPreview(){
|
fun OrderSummaryPreview() {
|
||||||
OrderSummaryScreen(
|
CupcakeTheme {
|
||||||
orderUiState = OrderUiState(0, "Test", "Test", "$300.00"),
|
OrderSummaryScreen(
|
||||||
onSendButtonClicked = { subject: String, summary: String -> },
|
orderUiState = OrderUiState(0, "Test", "Test", "$300.00"),
|
||||||
onCancelButtonClicked = {},
|
onSendButtonClicked = { subject: String, summary: String -> },
|
||||||
modifier = Modifier.fillMaxHeight()
|
onCancelButtonClicked = {},
|
||||||
)
|
modifier = Modifier.fillMaxHeight()
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,11 +14,11 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
-->
|
-->
|
||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">Cupcake</string>
|
<string name="app_name">Donut</string>
|
||||||
<string name="order_cupcakes">Order Cupcakes</string>
|
<string name="order_cupcakes">Pesan Donut</string>
|
||||||
<string name="one_cupcake">One Cupcake</string>
|
<string name="one_cupcake">Pesan 1 Donat</string>
|
||||||
<string name="six_cupcakes">Six Cupcakes</string>
|
<string name="six_cupcakes">Pesan Paket 6 Donut</string>
|
||||||
<string name="twelve_cupcakes">Twelve Cupcakes</string>
|
<string name="twelve_cupcakes">Pesan Paket 12 Donut</string>
|
||||||
<string name="choose_flavor">Choose Flavor</string>
|
<string name="choose_flavor">Choose Flavor</string>
|
||||||
<string name="vanilla">Vanilla</string>
|
<string name="vanilla">Vanilla</string>
|
||||||
<string name="chocolate">Chocolate</string>
|
<string name="chocolate">Chocolate</string>
|
||||||
@ -36,11 +36,11 @@
|
|||||||
<string name="pickup_date">Pickup date</string>
|
<string name="pickup_date">Pickup date</string>
|
||||||
<string name="subtotal_price">Subtotal %s</string>
|
<string name="subtotal_price">Subtotal %s</string>
|
||||||
<string name="total_price">Total %s</string>
|
<string name="total_price">Total %s</string>
|
||||||
<string name="new_cupcake_order">New Cupcake Order</string>
|
<string name="new_cupcake_order">New Donut Order</string>
|
||||||
<string name="order_details">Quantity: %1$s \nFlavor: %2$s \nPickup date: %3$s \nTotal: %4$s \n\nThank you!</string>
|
<string name="order_details">Quantity: %1$s \nFlavor: %2$s \nPickup date: %3$s \nTotal: %4$s \n\nThank you!</string>
|
||||||
<string name="back_button">Back</string>
|
<string name="back_button">Back</string>
|
||||||
<plurals name="cupcakes">
|
<plurals name="cupcakes">
|
||||||
<item quantity="one">%d cupcake</item>
|
<item quantity="one">%d Donut</item>
|
||||||
<item quantity="other">%d cupcakes</item>
|
<item quantity="other">%d Donut</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user