/* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ 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.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll 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.data.OrderUiState 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 values that represent the screens in the app */ 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, modifier: Modifier = Modifier ) { TopAppBar( title = { Text(stringResource(currentScreen.title)) }, colors = TopAppBarDefaults.mediumTopAppBarColors( containerColor = MaterialTheme.colorScheme.primaryContainer ), modifier = modifier, navigationIcon = { if (canNavigateBack) { IconButton(onClick = navigateUp) { Icon( imageVector = Icons.Filled.ArrowBack, contentDescription = stringResource(R.string.back_button) ) } } } ) } @Composable fun CupcakeApp( viewModel: OrderViewModel = viewModel(), navController: NavHostController = rememberNavController() ) { // Get current back stack entry val backStackEntry by navController.currentBackStackEntryAsState() // Get the name of the current screen val currentScreen = CupcakeScreen.valueOf( backStackEntry?.destination?.route ?: CupcakeScreen.Start.name ) Scaffold( topBar = { CupcakeAppBar( 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 .fillMaxSize() .verticalScroll(rememberScrollState()) .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() ) } } } } /** * Resets the [OrderUiState] and pops up to [CupcakeScreen.Start] */ private fun cancelOrderAndNavigateToStart( viewModel: OrderViewModel, navController: NavHostController ) { viewModel.resetOrder() navController.popBackStack(CupcakeScreen.Start.name, inclusive = false) } /** * Creates an intent to share order details */ private fun shareOrder(context: Context, subject: String, summary: String) { // Create an ACTION_SEND implicit intent with order details in the intent extras 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) ) ) }