From 22922b27deb5b294095e9089e698d596b165dd67 Mon Sep 17 00:00:00 2001 From: devoalda Date: Wed, 31 Jan 2024 22:02:16 +0800 Subject: [PATCH] Completed Tutorial :) --- .../java/com/example/cupcake/CupcakeScreen.kt | 134 ++++++++++++++++-- .../example/cupcake/ui/SelectOptionScreen.kt | 6 +- .../example/cupcake/ui/StartOrderScreen.kt | 6 +- .../com/example/cupcake/ui/SummaryScreen.kt | 22 +-- 4 files changed, 148 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/com/example/cupcake/CupcakeScreen.kt b/app/src/main/java/com/example/cupcake/CupcakeScreen.kt index 53e047f..f6d264c 100644 --- a/app/src/main/java/com/example/cupcake/CupcakeScreen.kt +++ b/app/src/main/java/com/example/cupcake/CupcakeScreen.kt @@ -15,39 +15,59 @@ */ 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.filled.ArrowBack import androidx.compose.material3.Icon import androidx.compose.material3.IconButton -import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar -import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue 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.lifecycle.viewmodel.compose.viewModel 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 com.example.cupcake.data.DataSource +import com.example.cupcake.ui.OrderSummaryScreen 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 fun CupcakeAppBar( + currentScreen: CupcakeScreen, canNavigateBack: Boolean, - navigateUp: () -> Unit, + navigateUp: () -> Unit = {}, modifier: Modifier = Modifier ) { TopAppBar( - title = { Text(stringResource(id = R.string.app_name)) }, - colors = TopAppBarDefaults.mediumTopAppBarColors( - containerColor = MaterialTheme.colorScheme.primaryContainer - ), + title = { Text(stringResource(currentScreen.title)) }, modifier = modifier, navigationIcon = { if (canNavigateBack) { @@ -60,6 +80,7 @@ fun CupcakeAppBar( } } ) + } @Composable @@ -67,16 +88,111 @@ fun CupcakeApp( viewModel: OrderViewModel = viewModel(), navController: NavHostController = rememberNavController() ) { + val backStackEntry by navController.currentBackStackEntryAsState() + val currentScreen = CupcakeScreen.valueOf( + backStackEntry?.destination?.route ?: CupcakeScreen.Start.name + ) Scaffold( topBar = { CupcakeAppBar( - canNavigateBack = false, - navigateUp = { /* TODO: implement back navigation */ } + currentScreen = currentScreen, + canNavigateBack = navController.previousBackStackEntry != null, + navigateUp = { navController.navigateUp() } ) + } ) { innerPadding -> 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) +} + diff --git a/app/src/main/java/com/example/cupcake/ui/SelectOptionScreen.kt b/app/src/main/java/com/example/cupcake/ui/SelectOptionScreen.kt index 84f7718..20caf5e 100644 --- a/app/src/main/java/com/example/cupcake/ui/SelectOptionScreen.kt +++ b/app/src/main/java/com/example/cupcake/ui/SelectOptionScreen.kt @@ -52,6 +52,8 @@ fun SelectOptionScreen( subtotal: String, options: List, onSelectionChanged: (String) -> Unit = {}, + onCancelButtonClicked: () -> Unit = {}, + onNextButtonClicked: () -> Unit = {}, modifier: Modifier = Modifier ) { var selectedValue by rememberSaveable { mutableStateOf("") } @@ -105,7 +107,7 @@ fun SelectOptionScreen( ) { OutlinedButton( modifier = Modifier.weight(1f), - onClick = {} + onClick = onCancelButtonClicked ) { Text(stringResource(R.string.cancel)) } @@ -113,7 +115,7 @@ fun SelectOptionScreen( modifier = Modifier.weight(1f), // the button is enabled when the user makes a selection enabled = selectedValue.isNotEmpty(), - onClick = {} + onClick = onNextButtonClicked ) { Text(stringResource(R.string.next)) } diff --git a/app/src/main/java/com/example/cupcake/ui/StartOrderScreen.kt b/app/src/main/java/com/example/cupcake/ui/StartOrderScreen.kt index beb5368..83c1f9e 100644 --- a/app/src/main/java/com/example/cupcake/ui/StartOrderScreen.kt +++ b/app/src/main/java/com/example/cupcake/ui/StartOrderScreen.kt @@ -49,6 +49,8 @@ import com.example.cupcake.ui.theme.CupcakeTheme @Composable fun StartOrderScreen( quantityOptions: List>, + onNextButtonClicked: (Int) -> Unit, + modifier: Modifier = Modifier ) { Column( @@ -83,7 +85,7 @@ fun StartOrderScreen( quantityOptions.forEach { item -> SelectQuantityButton( labelResourceId = item.first, - onClick = {} + onClick = { onNextButtonClicked(item.second) } ) } } @@ -114,9 +116,11 @@ fun StartOrderPreview() { CupcakeTheme { StartOrderScreen( quantityOptions = DataSource.quantityOptions, + onNextButtonClicked = {}, modifier = Modifier .fillMaxSize() .padding(dimensionResource(R.dimen.padding_medium)) ) } } + diff --git a/app/src/main/java/com/example/cupcake/ui/SummaryScreen.kt b/app/src/main/java/com/example/cupcake/ui/SummaryScreen.kt index 29a283e..196634f 100644 --- a/app/src/main/java/com/example/cupcake/ui/SummaryScreen.kt +++ b/app/src/main/java/com/example/cupcake/ui/SummaryScreen.kt @@ -48,6 +48,9 @@ import com.example.cupcake.ui.theme.CupcakeTheme @Composable fun OrderSummaryScreen( orderUiState: OrderUiState, + onCancelButtonClicked: () -> Unit, + onSendButtonClicked: (String, String) -> Unit, + modifier: Modifier = Modifier ) { val resources = LocalContext.current.resources @@ -103,13 +106,13 @@ fun OrderSummaryScreen( ) { Button( modifier = Modifier.fillMaxWidth(), - onClick = {} + onClick = { onSendButtonClicked(newOrder, orderSummary) } ) { Text(stringResource(R.string.send)) } OutlinedButton( modifier = Modifier.fillMaxWidth(), - onClick = {} + onClick = onCancelButtonClicked ) { Text(stringResource(R.string.cancel)) } @@ -121,10 +124,13 @@ fun OrderSummaryScreen( @Preview @Composable fun OrderSummaryPreview() { - CupcakeTheme { - OrderSummaryScreen( - orderUiState = OrderUiState(0, "Test", "Test", "$300.00"), - modifier = Modifier.fillMaxHeight() - ) - } + CupcakeTheme { + OrderSummaryScreen( + orderUiState = OrderUiState(0, "Test", "Test", "$300.00"), + onSendButtonClicked = { subject: String, summary: String -> }, + onCancelButtonClicked = {}, + modifier = Modifier.fillMaxHeight() + ) + } } +