Skip to content

Commit

Permalink
fix recipe id bug in EditRecipeViewModel
Browse files Browse the repository at this point in the history
  • Loading branch information
Cody Weaver authored and Cody Weaver committed Jan 16, 2024
1 parent d1b9d97 commit 814f2a2
Show file tree
Hide file tree
Showing 9 changed files with 164 additions and 106 deletions.
2 changes: 1 addition & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ android {
isMinifyEnabled = false
isDebuggable = true
isDefault = true
buildConfigField("Boolean", "DEBUG", "true")
buildConfigField("Boolean", "DEBUG", "false")
}

release {
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
android:supportsRtl="true"
android:theme="@android:style/Theme.DeviceDefault.NoActionBar"
tools:targetApi="34"
android:usesCleartextTraffic="false">
android:usesCleartextTraffic="true"> <!-- ONLY FOR EMULATOR USE -->
<activity
android:name=".MainActivity"
android:exported="true">
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/java/com/android/pocketalchemy/PaNavHost.kt
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ fun PaNavHost(
onFailure = {
navController.navigateAndPopAll("errOnLoginScreen")
},
coroutineScope
coroutineScope = coroutineScope
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
Expand All @@ -27,8 +27,7 @@ import com.android.pocketalchemy.ui.common.PaTopAppBar
private const val TAG = "EditRecipeScreen"

// Title and Icon Row Height
private const val TITLE_ROW_HEIGHT = 150
private const val DESC_ROW_HEIGHT = 150
private const val MAX_DESCRIPTION_HEIGHT = 100

/**
* Screen for creating and editing recipes.
Expand Down Expand Up @@ -57,64 +56,23 @@ fun EditRecipeScreen(
Column(
modifier = Modifier.padding(scaffoldPadding)
) {
Row( // Title, subtitle, icon
modifier = Modifier.padding(8.dp)
) {
////////////////////////////
// Recipe Title and subtitle
////////////////////////////
Column {
// Title
OutlinedTextField(
value = recipe.title,
onValueChange = {
editRecipeViewModel.updateRecipeState(
recipe.copy(title = it)
)
},
label = {
Text(
text = stringResource(id = R.string.recipe_title_label),
style = MaterialTheme.typography.headlineLarge
)
},
textStyle = MaterialTheme.typography.headlineMedium,
maxLines = 1,
TitleField(
recipe = recipe,
onUpdate = {
editRecipeViewModel.updateRecipeState(
recipe.copy(title = it)
)
}
}
)

//////////////
// Description
//////////////
Row(
modifier = Modifier
.height(DESC_ROW_HEIGHT.dp)
.fillMaxWidth(1f)
.padding(horizontal = 8.dp)
) {
OutlinedTextField(
value = recipe.description ?: "",
onValueChange = {
val description = if (it == "") {
null
} else {
it
}
editRecipeViewModel.updateRecipeState(
recipe.copy(description = description)
)
},
label = {
Text(
text = stringResource(id = R.string.recipe_description_label),
style = MaterialTheme.typography.bodyLarge
)
},
textStyle = MaterialTheme.typography.bodyLarge,
modifier = Modifier.fillMaxSize(1f)
)
}
DescriptionField(
recipe = recipe,
onUpdate = {
editRecipeViewModel.updateRecipeState(
recipe.copy(description = it)
)
}
)

Row( // Ingredients

Expand All @@ -124,48 +82,137 @@ fun EditRecipeScreen(

) { /* TODO: */ }

//////////////////////////
// Cancel and Save buttons
//////////////////////////
Row(
modifier = Modifier.padding(4.dp)
) {
// Save button
Box(
modifier = Modifier.padding(horizontal = 4.dp, vertical = 8.dp)
) {
Button(
onClick = {
editRecipeViewModel.saveRecipe()
navController.popBackStack()
},
modifier = Modifier.fillMaxWidth(.5f),
elevation = ButtonDefaults.buttonElevation(8.dp)
) {
Text(text = stringResource(id = R.string.save_recipe_button_label))
SaveButton(
onClick = {
editRecipeViewModel.saveRecipe()
navController.popBackStack()
}
}
)

// Cancel "go back" button
Box(
modifier = Modifier.padding(horizontal = 4.dp, vertical = 8.dp)
) {
Button(
onClick = {
editRecipeViewModel.clearRecipeId()
navController.popBackStack()
},
modifier = Modifier.fillMaxWidth(1f),
colors = ButtonDefaults.buttonColors(
containerColor = MaterialTheme.colorScheme.secondaryContainer,
contentColor = MaterialTheme.colorScheme.onSecondaryContainer
),
elevation = ButtonDefaults.buttonElevation(8.dp)
) {
Text(text = stringResource(id = R.string.go_back_button_label))
BackButton(
onClick = {
editRecipeViewModel.clearRecipeId()
navController.popBackStack()
}
}
)
}
}
}
}

/**
* Draws title field and requests updates from view model.
* @param recipe
* @param onUpdate
*/
@Composable
private fun TitleField(
recipe: Recipe,
onUpdate: (String) -> Unit
) {
Row(
modifier = Modifier.padding(8.dp)
) {
OutlinedTextField(
value = recipe.title,
onValueChange = {
onUpdate(it)
},
modifier = Modifier.fillMaxWidth(1f),
label = {
Text(
text = stringResource(id = R.string.recipe_title_label),
style = MaterialTheme.typography.headlineLarge
)
},
textStyle = MaterialTheme.typography.headlineMedium,
maxLines = 1,
)
}
}

/**
* Draws description field and requests updates from view model.
* @param recipe
* @param onUpdate
*/
@Composable
private fun DescriptionField(
recipe: Recipe,
onUpdate: (String?) -> Unit
) {
Row(
modifier = Modifier
.heightIn(max = MAX_DESCRIPTION_HEIGHT.dp)
.fillMaxWidth(1f)
.padding(horizontal = 8.dp)
) {
OutlinedTextField(
value = recipe.description ?: "",
onValueChange = {
val description = if (it == "") {
null
} else {
it
}
onUpdate(description)
},
label = {
Text(
text = stringResource(id = R.string.recipe_description_label),
style = MaterialTheme.typography.bodyLarge
)
},
textStyle = MaterialTheme.typography.bodyLarge,
modifier = Modifier.fillMaxSize(1f)
)
}
}

/**
* Save Recipe Button
*/
@Composable
private fun SaveButton(
onClick: () -> Unit
) {
Box(
modifier = Modifier.padding(horizontal = 4.dp, vertical = 8.dp)
) {
Button(
onClick = onClick,
modifier = Modifier.fillMaxWidth(.5f),
elevation = ButtonDefaults.buttonElevation(8.dp)
) {
Text(text = stringResource(id = R.string.save_recipe_button_label))
}
}
}

/**
* Back Button
*/
@Composable
private fun BackButton(
onClick: () -> Unit
) {
Box(
modifier = Modifier.padding(horizontal = 4.dp, vertical = 8.dp)
) {
Button(
onClick = onClick,
modifier = Modifier.fillMaxWidth(1f),
colors = ButtonDefaults.buttonColors(
containerColor = MaterialTheme.colorScheme.secondaryContainer,
contentColor = MaterialTheme.colorScheme.onSecondaryContainer
),
elevation = ButtonDefaults.buttonElevation(8.dp)
) {
Text(text = stringResource(id = R.string.go_back_button_label))
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import com.android.pocketalchemy.repository.AuthRepository
import com.android.pocketalchemy.repository.RecipeRepository
import com.google.firebase.firestore.toObject
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import javax.inject.Inject

Expand Down Expand Up @@ -40,7 +41,7 @@ class EditRecipeViewModel @Inject constructor(
* ui state model for EditRecipeScreen
*/
private var _recipeState: MutableState<Recipe>
= mutableStateOf(Recipe(userId = userId, id = recipeId ?: ""))
= mutableStateOf(Recipe(userId = userId, id = recipeId))
/**
* public accessor for ui state model
*/
Expand All @@ -55,9 +56,13 @@ class EditRecipeViewModel @Inject constructor(
fun setRecipeId(recipeId: String?) {
// no effect if already set
if (this.recipeId == null) {
val recipeDoc = recipeRepository.getRecipe(recipeId)
savedStateHandle[EDIT_RECIPE_ID_KEY] = recipeDoc.id
getRecipeSnapshot()
viewModelScope.launch(
Dispatchers.IO
) {
val recipeDoc = recipeRepository.getRecipe(recipeId)
savedStateHandle[EDIT_RECIPE_ID_KEY] = recipeDoc.id
getRecipeSnapshot()
}
}
}

Expand All @@ -74,7 +79,6 @@ class EditRecipeViewModel @Inject constructor(
* content when request completes.
*/
private fun getRecipeSnapshot() {
Log.d(TAG, "getRecipeSnapshot")
val recipeDoc = recipeRepository.getRecipe(recipeId)

recipeDoc.get()
Expand All @@ -92,15 +96,19 @@ class EditRecipeViewModel @Inject constructor(
* Updates ui state model
*/
fun updateRecipeState(recipe: Recipe) {
_recipeState.value = recipe.copy(id = recipeId ?: "")
viewModelScope.launch {
_recipeState.value = recipe.copy(id = recipeId)
}
}

/**
* Saves recipe and then clears recipe id.
*/
fun saveRecipe() {
// TODO: Check no required fields are empty!!!
viewModelScope.launch {
viewModelScope.launch(
Dispatchers.IO
) {
recipeRepository.insertRecipe(recipeState.value)
clearRecipeId()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import com.google.firebase.firestore.IgnoreExtraProperties
@IgnoreExtraProperties
@Keep
data class Recipe(
@DocumentId val id: String = "",
@DocumentId val id: String? = null,
val userId: String = "",
val title: String = "",
val kcalPerServing: Int = 0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
Expand Down Expand Up @@ -57,7 +56,6 @@ fun RecipeListCard(
.padding(8.dp)
.fillMaxWidth(1f)
) {
val coroutineScope = rememberCoroutineScope()

// Title
Row {
Expand Down
Loading

0 comments on commit 814f2a2

Please sign in to comment.