Completed Tutorial :)
This commit is contained in:
parent
4b6bf04748
commit
22922b27de
|
@ -15,39 +15,59 @@
|
||||||
*/
|
*/
|
||||||
package com.example.cupcake
|
package com.example.cupcake
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import androidx.annotation.StringRes
|
||||||
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
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
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TopAppBar
|
import androidx.compose.material3.TopAppBar
|
||||||
import androidx.compose.material3.TopAppBarDefaults
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.res.dimensionResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import androidx.navigation.NavHostController
|
import androidx.navigation.NavHostController
|
||||||
|
import androidx.navigation.compose.NavHost
|
||||||
|
import androidx.navigation.compose.composable
|
||||||
|
import androidx.navigation.compose.currentBackStackEntryAsState
|
||||||
import androidx.navigation.compose.rememberNavController
|
import androidx.navigation.compose.rememberNavController
|
||||||
|
import com.example.cupcake.data.DataSource
|
||||||
|
import com.example.cupcake.ui.OrderSummaryScreen
|
||||||
import com.example.cupcake.ui.OrderViewModel
|
import com.example.cupcake.ui.OrderViewModel
|
||||||
|
import com.example.cupcake.ui.SelectOptionScreen
|
||||||
|
import com.example.cupcake.ui.StartOrderScreen
|
||||||
|
|
||||||
|
|
||||||
|
enum class CupcakeScreen(@StringRes val title: Int) {
|
||||||
|
Start(title = R.string.app_name),
|
||||||
|
Flavor(title = R.string.choose_flavor),
|
||||||
|
Pickup(title = R.string.choose_pickup_date),
|
||||||
|
Summary(title = R.string.order_summary)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Composable that displays the topBar and displays back button if back navigation is possible.
|
* Composable that displays the topBar and displays back button if back navigation is possible.
|
||||||
*/
|
*/
|
||||||
@Composable
|
@Composable
|
||||||
fun CupcakeAppBar(
|
fun CupcakeAppBar(
|
||||||
|
currentScreen: CupcakeScreen,
|
||||||
canNavigateBack: Boolean,
|
canNavigateBack: Boolean,
|
||||||
navigateUp: () -> Unit,
|
navigateUp: () -> Unit = {},
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
title = { Text(stringResource(id = R.string.app_name)) },
|
title = { Text(stringResource(currentScreen.title)) },
|
||||||
colors = TopAppBarDefaults.mediumTopAppBarColors(
|
|
||||||
containerColor = MaterialTheme.colorScheme.primaryContainer
|
|
||||||
),
|
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
navigationIcon = {
|
navigationIcon = {
|
||||||
if (canNavigateBack) {
|
if (canNavigateBack) {
|
||||||
|
@ -60,6 +80,7 @@ fun CupcakeAppBar(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
@ -67,16 +88,111 @@ fun CupcakeApp(
|
||||||
viewModel: OrderViewModel = viewModel(),
|
viewModel: OrderViewModel = viewModel(),
|
||||||
navController: NavHostController = rememberNavController()
|
navController: NavHostController = rememberNavController()
|
||||||
) {
|
) {
|
||||||
|
val backStackEntry by navController.currentBackStackEntryAsState()
|
||||||
|
val currentScreen = CupcakeScreen.valueOf(
|
||||||
|
backStackEntry?.destination?.route ?: CupcakeScreen.Start.name
|
||||||
|
)
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
CupcakeAppBar(
|
CupcakeAppBar(
|
||||||
canNavigateBack = false,
|
currentScreen = currentScreen,
|
||||||
navigateUp = { /* TODO: implement back navigation */ }
|
canNavigateBack = navController.previousBackStackEntry != null,
|
||||||
|
navigateUp = { navController.navigateUp() }
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
) { innerPadding ->
|
) { innerPadding ->
|
||||||
val uiState by viewModel.uiState.collectAsState()
|
val uiState by viewModel.uiState.collectAsState()
|
||||||
|
|
||||||
|
|
||||||
|
NavHost(
|
||||||
|
navController = navController,
|
||||||
|
startDestination = CupcakeScreen.Start.name,
|
||||||
|
modifier = Modifier.padding(innerPadding)
|
||||||
|
) {
|
||||||
|
composable(route = CupcakeScreen.Start.name) {
|
||||||
|
StartOrderScreen(
|
||||||
|
quantityOptions = DataSource.quantityOptions,
|
||||||
|
onNextButtonClicked = {
|
||||||
|
viewModel.setQuantity(it)
|
||||||
|
navController.navigate(CupcakeScreen.Flavor.name)
|
||||||
|
},
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(dimensionResource(R.dimen.padding_medium))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
composable(route = CupcakeScreen.Flavor.name) {
|
||||||
|
val context = LocalContext.current
|
||||||
|
SelectOptionScreen(
|
||||||
|
subtotal = uiState.price,
|
||||||
|
onNextButtonClicked = { navController.navigate(CupcakeScreen.Pickup.name) },
|
||||||
|
onCancelButtonClicked = {
|
||||||
|
cancelOrderAndNavigateToStart(viewModel, navController)
|
||||||
|
},
|
||||||
|
options = DataSource.flavors.map { id -> context.resources.getString(id) },
|
||||||
|
onSelectionChanged = { viewModel.setFlavor(it) },
|
||||||
|
modifier = Modifier.fillMaxHeight()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
composable(route = CupcakeScreen.Pickup.name) {
|
||||||
|
SelectOptionScreen(
|
||||||
|
subtotal = uiState.price,
|
||||||
|
onNextButtonClicked = { navController.navigate(CupcakeScreen.Summary.name) },
|
||||||
|
onCancelButtonClicked = {
|
||||||
|
cancelOrderAndNavigateToStart(viewModel, navController)
|
||||||
|
},
|
||||||
|
options = uiState.pickupOptions,
|
||||||
|
onSelectionChanged = { viewModel.setDate(it) },
|
||||||
|
modifier = Modifier.fillMaxHeight()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
composable(route = CupcakeScreen.Summary.name) {
|
||||||
|
val context = LocalContext.current
|
||||||
|
OrderSummaryScreen(
|
||||||
|
orderUiState = uiState,
|
||||||
|
onCancelButtonClicked = {
|
||||||
|
cancelOrderAndNavigateToStart(viewModel, navController)
|
||||||
|
},
|
||||||
|
onSendButtonClicked = { subject: String, summary: String ->
|
||||||
|
shareOrder(context, subject = subject, summary = summary)
|
||||||
|
},
|
||||||
|
|
||||||
|
modifier = Modifier.fillMaxHeight()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun shareOrder(context: Context, subject: String, summary: String) {
|
||||||
|
val intent = Intent(Intent.ACTION_SEND).apply {
|
||||||
|
type = "text/plain"
|
||||||
|
putExtra(Intent.EXTRA_SUBJECT, subject)
|
||||||
|
putExtra(Intent.EXTRA_TEXT, summary)
|
||||||
|
}
|
||||||
|
|
||||||
|
context.startActivity(
|
||||||
|
Intent.createChooser(
|
||||||
|
intent,
|
||||||
|
context.getString(R.string.new_cupcake_order)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun cancelOrderAndNavigateToStart(
|
||||||
|
viewModel: OrderViewModel,
|
||||||
|
navController: NavHostController
|
||||||
|
) {
|
||||||
|
viewModel.resetOrder()
|
||||||
|
navController.popBackStack(CupcakeScreen.Start.name, inclusive = false)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,8 @@ fun SelectOptionScreen(
|
||||||
subtotal: String,
|
subtotal: String,
|
||||||
options: List<String>,
|
options: List<String>,
|
||||||
onSelectionChanged: (String) -> Unit = {},
|
onSelectionChanged: (String) -> Unit = {},
|
||||||
|
onCancelButtonClicked: () -> Unit = {},
|
||||||
|
onNextButtonClicked: () -> Unit = {},
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
var selectedValue by rememberSaveable { mutableStateOf("") }
|
var selectedValue by rememberSaveable { mutableStateOf("") }
|
||||||
|
@ -105,7 +107,7 @@ fun SelectOptionScreen(
|
||||||
) {
|
) {
|
||||||
OutlinedButton(
|
OutlinedButton(
|
||||||
modifier = Modifier.weight(1f),
|
modifier = Modifier.weight(1f),
|
||||||
onClick = {}
|
onClick = onCancelButtonClicked
|
||||||
) {
|
) {
|
||||||
Text(stringResource(R.string.cancel))
|
Text(stringResource(R.string.cancel))
|
||||||
}
|
}
|
||||||
|
@ -113,7 +115,7 @@ fun SelectOptionScreen(
|
||||||
modifier = Modifier.weight(1f),
|
modifier = Modifier.weight(1f),
|
||||||
// the button is enabled when the user makes a selection
|
// the button is enabled when the user makes a selection
|
||||||
enabled = selectedValue.isNotEmpty(),
|
enabled = selectedValue.isNotEmpty(),
|
||||||
onClick = {}
|
onClick = onNextButtonClicked
|
||||||
) {
|
) {
|
||||||
Text(stringResource(R.string.next))
|
Text(stringResource(R.string.next))
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,6 +49,8 @@ import com.example.cupcake.ui.theme.CupcakeTheme
|
||||||
@Composable
|
@Composable
|
||||||
fun StartOrderScreen(
|
fun StartOrderScreen(
|
||||||
quantityOptions: List<Pair<Int, Int>>,
|
quantityOptions: List<Pair<Int, Int>>,
|
||||||
|
onNextButtonClicked: (Int) -> Unit,
|
||||||
|
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
|
@ -83,7 +85,7 @@ fun StartOrderScreen(
|
||||||
quantityOptions.forEach { item ->
|
quantityOptions.forEach { item ->
|
||||||
SelectQuantityButton(
|
SelectQuantityButton(
|
||||||
labelResourceId = item.first,
|
labelResourceId = item.first,
|
||||||
onClick = {}
|
onClick = { onNextButtonClicked(item.second) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -114,9 +116,11 @@ fun StartOrderPreview() {
|
||||||
CupcakeTheme {
|
CupcakeTheme {
|
||||||
StartOrderScreen(
|
StartOrderScreen(
|
||||||
quantityOptions = DataSource.quantityOptions,
|
quantityOptions = DataSource.quantityOptions,
|
||||||
|
onNextButtonClicked = {},
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.padding(dimensionResource(R.dimen.padding_medium))
|
.padding(dimensionResource(R.dimen.padding_medium))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,9 @@ import com.example.cupcake.ui.theme.CupcakeTheme
|
||||||
@Composable
|
@Composable
|
||||||
fun OrderSummaryScreen(
|
fun OrderSummaryScreen(
|
||||||
orderUiState: OrderUiState,
|
orderUiState: OrderUiState,
|
||||||
|
onCancelButtonClicked: () -> Unit,
|
||||||
|
onSendButtonClicked: (String, String) -> Unit,
|
||||||
|
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
val resources = LocalContext.current.resources
|
val resources = LocalContext.current.resources
|
||||||
|
@ -103,13 +106,13 @@ fun OrderSummaryScreen(
|
||||||
) {
|
) {
|
||||||
Button(
|
Button(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
onClick = {}
|
onClick = { onSendButtonClicked(newOrder, orderSummary) }
|
||||||
) {
|
) {
|
||||||
Text(stringResource(R.string.send))
|
Text(stringResource(R.string.send))
|
||||||
}
|
}
|
||||||
OutlinedButton(
|
OutlinedButton(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
onClick = {}
|
onClick = onCancelButtonClicked
|
||||||
) {
|
) {
|
||||||
Text(stringResource(R.string.cancel))
|
Text(stringResource(R.string.cancel))
|
||||||
}
|
}
|
||||||
|
@ -121,10 +124,13 @@ fun OrderSummaryScreen(
|
||||||
@Preview
|
@Preview
|
||||||
@Composable
|
@Composable
|
||||||
fun OrderSummaryPreview() {
|
fun OrderSummaryPreview() {
|
||||||
CupcakeTheme {
|
CupcakeTheme {
|
||||||
OrderSummaryScreen(
|
OrderSummaryScreen(
|
||||||
orderUiState = OrderUiState(0, "Test", "Test", "$300.00"),
|
orderUiState = OrderUiState(0, "Test", "Test", "$300.00"),
|
||||||
modifier = Modifier.fillMaxHeight()
|
onSendButtonClicked = { subject: String, summary: String -> },
|
||||||
)
|
onCancelButtonClicked = {},
|
||||||
}
|
modifier = Modifier.fillMaxHeight()
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue