diff --git a/app/src/main/java/gq/kirmanak/mealient/data/add/AddRecipeDataSource.kt b/app/src/main/java/gq/kirmanak/mealient/data/add/AddRecipeDataSource.kt index 97a3af0..dc5769b 100644 --- a/app/src/main/java/gq/kirmanak/mealient/data/add/AddRecipeDataSource.kt +++ b/app/src/main/java/gq/kirmanak/mealient/data/add/AddRecipeDataSource.kt @@ -1,7 +1,6 @@ package gq.kirmanak.mealient.data.add -import gq.kirmanak.mealient.datasource.v0.models.AddRecipeRequestV0 - interface AddRecipeDataSource { - suspend fun addRecipe(recipe: AddRecipeRequestV0): String + + suspend fun addRecipe(recipe: AddRecipeInfo): String } \ No newline at end of file diff --git a/app/src/main/java/gq/kirmanak/mealient/data/add/AddRecipeInfo.kt b/app/src/main/java/gq/kirmanak/mealient/data/add/AddRecipeInfo.kt new file mode 100644 index 0000000..69c2ee9 --- /dev/null +++ b/app/src/main/java/gq/kirmanak/mealient/data/add/AddRecipeInfo.kt @@ -0,0 +1,46 @@ +package gq.kirmanak.mealient.data.add + +data class AddRecipeInfo( + val name: String = "", + val description: String = "", + val image: String = "", + val recipeYield: String = "", + val recipeIngredient: List = emptyList(), + val recipeInstructions: List = emptyList(), + val slug: String = "", + val filePath: String = "", + val tags: List = emptyList(), + val categories: List = emptyList(), + val notes: List = emptyList(), + val extras: Map = emptyMap(), + val assets: List = emptyList(), + val settings: AddRecipeSettingsInfo = AddRecipeSettingsInfo(), +) + +data class AddRecipeSettingsInfo( + val disableAmount: Boolean = true, + val disableComments: Boolean = false, + val landscapeView: Boolean = true, + val public: Boolean = true, + val showAssets: Boolean = true, + val showNutrition: Boolean = true, +) + +data class AddRecipeNoteInfo( + val title: String = "", + val text: String = "", +) + +data class AddRecipeIngredientInfo( + val disableAmount: Boolean = true, + val food: String? = null, + val note: String = "", + val quantity: Int = 1, + val title: String? = null, + val unit: String? = null, +) + +data class AddRecipeInstructionInfo( + val title: String = "", + val text: String = "", +) diff --git a/app/src/main/java/gq/kirmanak/mealient/data/add/AddRecipeRepo.kt b/app/src/main/java/gq/kirmanak/mealient/data/add/AddRecipeRepo.kt index 952ed68..a0c7620 100644 --- a/app/src/main/java/gq/kirmanak/mealient/data/add/AddRecipeRepo.kt +++ b/app/src/main/java/gq/kirmanak/mealient/data/add/AddRecipeRepo.kt @@ -1,13 +1,12 @@ package gq.kirmanak.mealient.data.add -import gq.kirmanak.mealient.datasource.v0.models.AddRecipeRequestV0 import kotlinx.coroutines.flow.Flow interface AddRecipeRepo { - val addRecipeRequestFlow: Flow + val addRecipeRequestFlow: Flow - suspend fun preserve(recipe: AddRecipeRequestV0) + suspend fun preserve(recipe: AddRecipeInfo) suspend fun clear() diff --git a/app/src/main/java/gq/kirmanak/mealient/data/add/impl/AddRecipeRepoImpl.kt b/app/src/main/java/gq/kirmanak/mealient/data/add/impl/AddRecipeRepoImpl.kt index 3356aa4..9043ca8 100644 --- a/app/src/main/java/gq/kirmanak/mealient/data/add/impl/AddRecipeRepoImpl.kt +++ b/app/src/main/java/gq/kirmanak/mealient/data/add/impl/AddRecipeRepoImpl.kt @@ -1,10 +1,10 @@ package gq.kirmanak.mealient.data.add.impl import gq.kirmanak.mealient.data.add.AddRecipeDataSource +import gq.kirmanak.mealient.data.add.AddRecipeInfo import gq.kirmanak.mealient.data.add.AddRecipeRepo -import gq.kirmanak.mealient.datasource.v0.models.AddRecipeRequestV0 import gq.kirmanak.mealient.datastore.recipe.AddRecipeStorage -import gq.kirmanak.mealient.extensions.toAddRecipeRequest +import gq.kirmanak.mealient.extensions.toAddRecipeInfo import gq.kirmanak.mealient.extensions.toDraft import gq.kirmanak.mealient.logging.Logger import kotlinx.coroutines.flow.Flow @@ -20,10 +20,10 @@ class AddRecipeRepoImpl @Inject constructor( private val logger: Logger, ) : AddRecipeRepo { - override val addRecipeRequestFlow: Flow - get() = addRecipeStorage.updates.map { it.toAddRecipeRequest() } + override val addRecipeRequestFlow: Flow + get() = addRecipeStorage.updates.map { it.toAddRecipeInfo() } - override suspend fun preserve(recipe: AddRecipeRequestV0) { + override suspend fun preserve(recipe: AddRecipeInfo) { logger.v { "preserveRecipe() called with: recipe = $recipe" } addRecipeStorage.save(recipe.toDraft()) } diff --git a/app/src/main/java/gq/kirmanak/mealient/data/network/MealieDataSourceWrapper.kt b/app/src/main/java/gq/kirmanak/mealient/data/network/MealieDataSourceWrapper.kt index 1bca823..4f8f2ea 100644 --- a/app/src/main/java/gq/kirmanak/mealient/data/network/MealieDataSourceWrapper.kt +++ b/app/src/main/java/gq/kirmanak/mealient/data/network/MealieDataSourceWrapper.kt @@ -1,6 +1,7 @@ package gq.kirmanak.mealient.data.network import gq.kirmanak.mealient.data.add.AddRecipeDataSource +import gq.kirmanak.mealient.data.add.AddRecipeInfo import gq.kirmanak.mealient.data.auth.AuthRepo import gq.kirmanak.mealient.data.baseurl.ServerInfoRepo import gq.kirmanak.mealient.data.baseurl.ServerVersion @@ -10,10 +11,11 @@ import gq.kirmanak.mealient.data.recipes.network.RecipeSummaryInfo import gq.kirmanak.mealient.datasource.NetworkError import gq.kirmanak.mealient.datasource.runCatchingExceptCancel import gq.kirmanak.mealient.datasource.v0.MealieDataSourceV0 -import gq.kirmanak.mealient.datasource.v0.models.AddRecipeRequestV0 import gq.kirmanak.mealient.datasource.v1.MealieDataSourceV1 import gq.kirmanak.mealient.extensions.toFullRecipeInfo import gq.kirmanak.mealient.extensions.toRecipeSummaryInfo +import gq.kirmanak.mealient.extensions.toV0Request +import gq.kirmanak.mealient.extensions.toV1Request import javax.inject.Inject import javax.inject.Singleton @@ -21,21 +23,26 @@ import javax.inject.Singleton class MealieDataSourceWrapper @Inject constructor( private val serverInfoRepo: ServerInfoRepo, private val authRepo: AuthRepo, - private val v0source: MealieDataSourceV0, + private val v0Source: MealieDataSourceV0, private val v1Source: MealieDataSourceV1, ) : AddRecipeDataSource, RecipeDataSource { - override suspend fun addRecipe(recipe: AddRecipeRequestV0): String = withAuthHeader { token -> - v0source.addRecipe(getUrl(), token, recipe) + override suspend fun addRecipe( + recipe: AddRecipeInfo, + ): String = makeCall { token, url, version -> + when (version) { + ServerVersion.V0 -> v0Source.addRecipe(url, token, recipe.toV0Request()) + ServerVersion.V1 -> v1Source.addRecipe(url, token, recipe.toV1Request()) + } } override suspend fun requestRecipes( - start: Int, limit: Int - ): List = withAuthHeader { token -> - val url = getUrl() - when (getVersion()) { + start: Int, + limit: Int, + ): List = makeCall { token, url, version -> + when (version) { ServerVersion.V0 -> { - v0source.requestRecipes(url, token, start, limit).map { it.toRecipeSummaryInfo() } + v0Source.requestRecipes(url, token, start, limit).map { it.toRecipeSummaryInfo() } } ServerVersion.V1 -> { // Imagine start is 30 and limit is 15. It means that we already have page 1 and 2, now we need page 3 @@ -45,26 +52,25 @@ class MealieDataSourceWrapper @Inject constructor( } } - override suspend fun requestRecipeInfo(slug: String): FullRecipeInfo = withAuthHeader { token -> - val url = getUrl() - when (getVersion()) { - ServerVersion.V0 -> v0source.requestRecipeInfo(url, token, slug).toFullRecipeInfo() + override suspend fun requestRecipeInfo( + slug: String, + ): FullRecipeInfo = makeCall { token, url, version -> + when (version) { + ServerVersion.V0 -> v0Source.requestRecipeInfo(url, token, slug).toFullRecipeInfo() ServerVersion.V1 -> v1Source.requestRecipeInfo(url, token, slug).toFullRecipeInfo() } } - private suspend fun getUrl() = serverInfoRepo.requireUrl() - - private suspend fun getVersion() = serverInfoRepo.getVersion() - - private suspend inline fun withAuthHeader(block: (String?) -> T): T { + private suspend inline fun makeCall(block: (String?, String, ServerVersion) -> T): T { val authHeader = authRepo.getAuthHeader() - return runCatchingExceptCancel { block(authHeader) }.getOrElse { + val url = serverInfoRepo.requireUrl() + val version = serverInfoRepo.getVersion() + return runCatchingExceptCancel { block(authHeader, url, version) }.getOrElse { if (it is NetworkError.Unauthorized) { authRepo.invalidateAuthHeader() // Trying again with new authentication header val newHeader = authRepo.getAuthHeader() - if (newHeader == authHeader) throw it else block(newHeader) + if (newHeader == authHeader) throw it else block(newHeader, url, version) } else { throw it } diff --git a/app/src/main/java/gq/kirmanak/mealient/extensions/RemoteToLocalMappings.kt b/app/src/main/java/gq/kirmanak/mealient/extensions/RemoteToLocalMappings.kt index 89b615e..d45668e 100644 --- a/app/src/main/java/gq/kirmanak/mealient/extensions/RemoteToLocalMappings.kt +++ b/app/src/main/java/gq/kirmanak/mealient/extensions/RemoteToLocalMappings.kt @@ -1,5 +1,6 @@ package gq.kirmanak.mealient.extensions +import gq.kirmanak.mealient.data.add.* import gq.kirmanak.mealient.data.baseurl.VersionInfo import gq.kirmanak.mealient.data.recipes.network.FullRecipeInfo import gq.kirmanak.mealient.data.recipes.network.RecipeIngredientInfo @@ -78,19 +79,19 @@ fun VersionResponseV0.toVersionInfo() = VersionInfo(version) fun VersionResponseV1.toVersionInfo() = VersionInfo(version) -fun AddRecipeDraft.toAddRecipeRequest() = AddRecipeRequestV0( +fun AddRecipeDraft.toAddRecipeInfo() = AddRecipeInfo( name = recipeName, description = recipeDescription, recipeYield = recipeYield, - recipeIngredient = recipeIngredients.map { AddRecipeIngredientV0(note = it) }, - recipeInstructions = recipeInstructions.map { AddRecipeInstructionV0(text = it) }, - settings = AddRecipeSettingsV0( + recipeIngredient = recipeIngredients.map { AddRecipeIngredientInfo(note = it) }, + recipeInstructions = recipeInstructions.map { AddRecipeInstructionInfo(text = it) }, + settings = AddRecipeSettingsInfo( public = isRecipePublic, disableComments = areCommentsDisabled, ) ) -fun AddRecipeRequestV0.toDraft(): AddRecipeDraft = AddRecipeDraft( +fun AddRecipeInfo.toDraft(): AddRecipeDraft = AddRecipeDraft( recipeName = name, recipeDescription = description, recipeYield = recipeYield, @@ -159,3 +160,93 @@ fun GetRecipeInstructionResponseV1.toRecipeInstructionInfo() = RecipeInstruction title = title, text = text ) + +fun AddRecipeInfo.toV0Request() = AddRecipeRequestV0( + name = name, + description = description, + image = image, + recipeYield = recipeYield, + recipeIngredient = recipeIngredient.map { it.toV0Ingredient() }, + recipeInstructions = recipeInstructions.map { it.toV0Instruction() }, + slug = slug, + filePath = filePath, + tags = tags, + categories = categories, + notes = notes.map { it.toV0Note() }, + extras = extras, + assets = assets, + settings = settings.toV0Settings(), +) + +private fun AddRecipeSettingsInfo.toV0Settings() = AddRecipeSettingsV0( + disableAmount = disableAmount, + disableComments = disableComments, + landscapeView = landscapeView, + public = public, + showAssets = showAssets, + showNutrition = showNutrition, +) + +private fun AddRecipeNoteInfo.toV0Note() = AddRecipeNoteV0( + title = title, + text = text, +) + +private fun AddRecipeIngredientInfo.toV0Ingredient() = AddRecipeIngredientV0( + disableAmount = disableAmount, + food = food, + note = note, + quantity = quantity, + title = title, + unit = unit +) + +private fun AddRecipeInstructionInfo.toV0Instruction() = AddRecipeInstructionV0( + title = title, + text = text, +) + +fun AddRecipeInfo.toV1Request() = AddRecipeRequestV1( + name = name, + description = description, + image = image, + recipeYield = recipeYield, + recipeIngredient = recipeIngredient.map { it.toV1Ingredient() }, + recipeInstructions = recipeInstructions.map { it.toV1Instruction() }, + slug = slug, + filePath = filePath, + tags = tags, + categories = categories, + notes = notes.map { it.toV1Note() }, + extras = extras, + assets = assets, + settings = settings.toV1Settings(), +) + +private fun AddRecipeSettingsInfo.toV1Settings() = AddRecipeSettingsV1( + disableAmount = disableAmount, + disableComments = disableComments, + landscapeView = landscapeView, + public = public, + showAssets = showAssets, + showNutrition = showNutrition, +) + +private fun AddRecipeNoteInfo.toV1Note() = AddRecipeNoteV1( + title = title, + text = text, +) + +private fun AddRecipeIngredientInfo.toV1Ingredient() = AddRecipeIngredientV1( + disableAmount = disableAmount, + food = food, + note = note, + quantity = quantity, + title = title, + unit = unit +) + +private fun AddRecipeInstructionInfo.toV1Instruction() = AddRecipeInstructionV1( + title = title, + text = text, +) \ No newline at end of file diff --git a/app/src/main/java/gq/kirmanak/mealient/ui/add/AddRecipeFragment.kt b/app/src/main/java/gq/kirmanak/mealient/ui/add/AddRecipeFragment.kt index d6e655c..a746d50 100644 --- a/app/src/main/java/gq/kirmanak/mealient/ui/add/AddRecipeFragment.kt +++ b/app/src/main/java/gq/kirmanak/mealient/ui/add/AddRecipeFragment.kt @@ -12,12 +12,12 @@ import androidx.fragment.app.viewModels import by.kirich1409.viewbindingdelegate.viewBinding import dagger.hilt.android.AndroidEntryPoint import gq.kirmanak.mealient.R +import gq.kirmanak.mealient.data.add.AddRecipeInfo +import gq.kirmanak.mealient.data.add.AddRecipeIngredientInfo +import gq.kirmanak.mealient.data.add.AddRecipeInstructionInfo +import gq.kirmanak.mealient.data.add.AddRecipeSettingsInfo import gq.kirmanak.mealient.databinding.FragmentAddRecipeBinding import gq.kirmanak.mealient.databinding.ViewSingleInputBinding -import gq.kirmanak.mealient.datasource.v0.models.AddRecipeIngredientV0 -import gq.kirmanak.mealient.datasource.v0.models.AddRecipeInstructionV0 -import gq.kirmanak.mealient.datasource.v0.models.AddRecipeRequestV0 -import gq.kirmanak.mealient.datasource.v0.models.AddRecipeSettingsV0 import gq.kirmanak.mealient.extensions.checkIfInputIsEmpty import gq.kirmanak.mealient.extensions.collectWhenViewResumed import gq.kirmanak.mealient.logging.Logger @@ -122,14 +122,15 @@ class AddRecipeFragment : Fragment(R.layout.fragment_add_recipe) { private fun saveValues() = with(binding) { logger.v { "saveValues() called" } - val instructions = parseInputRows(instructionsFlow).map { AddRecipeInstructionV0(text = it) } - val ingredients = parseInputRows(ingredientsFlow).map { AddRecipeIngredientV0(note = it) } - val settings = AddRecipeSettingsV0( + val instructions = + parseInputRows(instructionsFlow).map { AddRecipeInstructionInfo(text = it) } + val ingredients = parseInputRows(ingredientsFlow).map { AddRecipeIngredientInfo(note = it) } + val settings = AddRecipeSettingsInfo( public = publicRecipe.isChecked, disableComments = disableComments.isChecked, ) viewModel.preserve( - AddRecipeRequestV0( + AddRecipeInfo( name = recipeNameInput.text.toString(), description = recipeDescriptionInput.text.toString(), recipeYield = recipeYieldInput.text.toString(), @@ -148,7 +149,7 @@ class AddRecipeFragment : Fragment(R.layout.fragment_add_recipe) { .filterNot { it.isBlank() } .toList() - private fun onSavedInputLoaded(request: AddRecipeRequestV0) = with(binding) { + private fun onSavedInputLoaded(request: AddRecipeInfo) = with(binding) { logger.v { "onSavedInputLoaded() called with: request = $request" } recipeNameInput.setText(request.name) recipeDescriptionInput.setText(request.description) diff --git a/app/src/main/java/gq/kirmanak/mealient/ui/add/AddRecipeViewModel.kt b/app/src/main/java/gq/kirmanak/mealient/ui/add/AddRecipeViewModel.kt index 231638f..982e56f 100644 --- a/app/src/main/java/gq/kirmanak/mealient/ui/add/AddRecipeViewModel.kt +++ b/app/src/main/java/gq/kirmanak/mealient/ui/add/AddRecipeViewModel.kt @@ -3,9 +3,9 @@ package gq.kirmanak.mealient.ui.add import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel +import gq.kirmanak.mealient.data.add.AddRecipeInfo import gq.kirmanak.mealient.data.add.AddRecipeRepo import gq.kirmanak.mealient.datasource.runCatchingExceptCancel -import gq.kirmanak.mealient.datasource.v0.models.AddRecipeRequestV0 import gq.kirmanak.mealient.logging.Logger import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.Flow @@ -23,8 +23,8 @@ class AddRecipeViewModel @Inject constructor( private val _addRecipeResultChannel = Channel(Channel.UNLIMITED) val addRecipeResult: Flow get() = _addRecipeResultChannel.receiveAsFlow() - private val _preservedAddRecipeRequestChannel = Channel(Channel.UNLIMITED) - val preservedAddRecipeRequest: Flow + private val _preservedAddRecipeRequestChannel = Channel(Channel.UNLIMITED) + val preservedAddRecipeRequest: Flow get() = _preservedAddRecipeRequestChannel.receiveAsFlow() fun loadPreservedRequest() { @@ -47,7 +47,7 @@ class AddRecipeViewModel @Inject constructor( } } - fun preserve(request: AddRecipeRequestV0) { + fun preserve(request: AddRecipeInfo) { logger.v { "preserve() called with: request = $request" } viewModelScope.launch { addRecipeRepo.preserve(request) } } diff --git a/app/src/test/java/gq/kirmanak/mealient/extensions/RemoteToLocalMappingsTest.kt b/app/src/test/java/gq/kirmanak/mealient/extensions/RemoteToLocalMappingsTest.kt index 08b6749..a43e6c9 100644 --- a/app/src/test/java/gq/kirmanak/mealient/extensions/RemoteToLocalMappingsTest.kt +++ b/app/src/test/java/gq/kirmanak/mealient/extensions/RemoteToLocalMappingsTest.kt @@ -1,10 +1,10 @@ package gq.kirmanak.mealient.extensions import com.google.common.truth.Truth.assertThat -import gq.kirmanak.mealient.datasource.v0.models.AddRecipeIngredientV0 -import gq.kirmanak.mealient.datasource.v0.models.AddRecipeInstructionV0 -import gq.kirmanak.mealient.datasource.v0.models.AddRecipeRequestV0 -import gq.kirmanak.mealient.datasource.v0.models.AddRecipeSettingsV0 +import gq.kirmanak.mealient.data.add.AddRecipeInfo +import gq.kirmanak.mealient.data.add.AddRecipeIngredientInfo +import gq.kirmanak.mealient.data.add.AddRecipeInstructionInfo +import gq.kirmanak.mealient.data.add.AddRecipeSettingsInfo import gq.kirmanak.mealient.datastore.recipe.AddRecipeDraft import org.junit.Test @@ -22,42 +22,42 @@ class RemoteToLocalMappingsTest { areCommentsDisabled = true, ) - val expected = AddRecipeRequestV0( + val expected = AddRecipeInfo( name = "Recipe name", description = "Recipe description", recipeYield = "Recipe yield", recipeIngredient = listOf( - AddRecipeIngredientV0(note = "Recipe ingredient 1"), - AddRecipeIngredientV0(note = "Recipe ingredient 2") + AddRecipeIngredientInfo(note = "Recipe ingredient 1"), + AddRecipeIngredientInfo(note = "Recipe ingredient 2") ), recipeInstructions = listOf( - AddRecipeInstructionV0(text = "Recipe instruction 1"), - AddRecipeInstructionV0(text = "Recipe instruction 2") + AddRecipeInstructionInfo(text = "Recipe instruction 1"), + AddRecipeInstructionInfo(text = "Recipe instruction 2") ), - settings = AddRecipeSettingsV0( + settings = AddRecipeSettingsInfo( public = false, disableComments = true, ) ) - assertThat(input.toAddRecipeRequest()).isEqualTo(expected) + assertThat(input.toAddRecipeInfo()).isEqualTo(expected) } @Test fun `when toDraft then fills fields correctly`() { - val request = AddRecipeRequestV0( + val request = AddRecipeInfo( name = "Recipe name", description = "Recipe description", recipeYield = "Recipe yield", recipeIngredient = listOf( - AddRecipeIngredientV0(note = "Recipe ingredient 1"), - AddRecipeIngredientV0(note = "Recipe ingredient 2") + AddRecipeIngredientInfo(note = "Recipe ingredient 1"), + AddRecipeIngredientInfo(note = "Recipe ingredient 2") ), recipeInstructions = listOf( - AddRecipeInstructionV0(text = "Recipe instruction 1"), - AddRecipeInstructionV0(text = "Recipe instruction 2") + AddRecipeInstructionInfo(text = "Recipe instruction 1"), + AddRecipeInstructionInfo(text = "Recipe instruction 2") ), - settings = AddRecipeSettingsV0( + settings = AddRecipeSettingsInfo( public = false, disableComments = true, ) diff --git a/app/src/test/java/gq/kirmanak/mealient/ui/add/AddRecipeViewModelTest.kt b/app/src/test/java/gq/kirmanak/mealient/ui/add/AddRecipeViewModelTest.kt index 3e95fcd..898b2f1 100644 --- a/app/src/test/java/gq/kirmanak/mealient/ui/add/AddRecipeViewModelTest.kt +++ b/app/src/test/java/gq/kirmanak/mealient/ui/add/AddRecipeViewModelTest.kt @@ -1,8 +1,8 @@ package gq.kirmanak.mealient.ui.add import com.google.common.truth.Truth.assertThat +import gq.kirmanak.mealient.data.add.AddRecipeInfo import gq.kirmanak.mealient.data.add.AddRecipeRepo -import gq.kirmanak.mealient.datasource.v0.models.AddRecipeRequestV0 import gq.kirmanak.mealient.logging.Logger import io.mockk.MockKAnnotations import io.mockk.coEvery @@ -61,21 +61,21 @@ class AddRecipeViewModelTest { @Test fun `when preserve then doesn't update UI`() { - coEvery { addRecipeRepo.addRecipeRequestFlow } returns flowOf(AddRecipeRequestV0()) - subject.preserve(AddRecipeRequestV0()) + coEvery { addRecipeRepo.addRecipeRequestFlow } returns flowOf(AddRecipeInfo()) + subject.preserve(AddRecipeInfo()) coVerify(inverse = true) { addRecipeRepo.addRecipeRequestFlow } } @Test fun `when preservedAddRecipeRequest without loadPreservedRequest then empty`() = runTest { - coEvery { addRecipeRepo.addRecipeRequestFlow } returns flowOf(AddRecipeRequestV0()) + coEvery { addRecipeRepo.addRecipeRequestFlow } returns flowOf(AddRecipeInfo()) val actual = withTimeoutOrNull(10) { subject.preservedAddRecipeRequest.firstOrNull() } assertThat(actual).isNull() } @Test fun `when loadPreservedRequest then updates preservedAddRecipeRequest`() = runTest { - val expected = AddRecipeRequestV0() + val expected = AddRecipeInfo() coEvery { addRecipeRepo.addRecipeRequestFlow } returns flowOf(expected) subject.loadPreservedRequest() assertThat(subject.preservedAddRecipeRequest.first()).isSameInstanceAs(expected) @@ -83,7 +83,7 @@ class AddRecipeViewModelTest { @Test fun `when clear then updates preservedAddRecipeRequest`() = runTest { - val expected = AddRecipeRequestV0() + val expected = AddRecipeInfo() coEvery { addRecipeRepo.addRecipeRequestFlow } returns flowOf(expected) subject.clear() assertThat(subject.preservedAddRecipeRequest.first()).isSameInstanceAs(expected) diff --git a/datasource/src/main/kotlin/gq/kirmanak/mealient/datasource/v1/MealieDataSourceV1.kt b/datasource/src/main/kotlin/gq/kirmanak/mealient/datasource/v1/MealieDataSourceV1.kt index 7c888ec..0af5545 100644 --- a/datasource/src/main/kotlin/gq/kirmanak/mealient/datasource/v1/MealieDataSourceV1.kt +++ b/datasource/src/main/kotlin/gq/kirmanak/mealient/datasource/v1/MealieDataSourceV1.kt @@ -1,6 +1,6 @@ package gq.kirmanak.mealient.datasource.v1 -import gq.kirmanak.mealient.datasource.v0.models.AddRecipeRequestV0 +import gq.kirmanak.mealient.datasource.v1.models.AddRecipeRequestV1 import gq.kirmanak.mealient.datasource.v1.models.GetRecipeResponseV1 import gq.kirmanak.mealient.datasource.v1.models.GetRecipeSummaryResponseV1 import gq.kirmanak.mealient.datasource.v1.models.VersionResponseV1 @@ -10,7 +10,7 @@ interface MealieDataSourceV1 { suspend fun addRecipe( baseUrl: String, token: String?, - recipe: AddRecipeRequestV0, + recipe: AddRecipeRequestV1, ): String /** diff --git a/datasource/src/main/kotlin/gq/kirmanak/mealient/datasource/v1/MealieDataSourceV1Impl.kt b/datasource/src/main/kotlin/gq/kirmanak/mealient/datasource/v1/MealieDataSourceV1Impl.kt index 0857a91..8edd86f 100644 --- a/datasource/src/main/kotlin/gq/kirmanak/mealient/datasource/v1/MealieDataSourceV1Impl.kt +++ b/datasource/src/main/kotlin/gq/kirmanak/mealient/datasource/v1/MealieDataSourceV1Impl.kt @@ -3,11 +3,7 @@ package gq.kirmanak.mealient.datasource.v1 import gq.kirmanak.mealient.datasource.NetworkError import gq.kirmanak.mealient.datasource.NetworkRequestWrapper import gq.kirmanak.mealient.datasource.decode -import gq.kirmanak.mealient.datasource.v0.models.AddRecipeRequestV0 -import gq.kirmanak.mealient.datasource.v1.models.ErrorDetailV1 -import gq.kirmanak.mealient.datasource.v1.models.GetRecipeResponseV1 -import gq.kirmanak.mealient.datasource.v1.models.GetRecipeSummaryResponseV1 -import gq.kirmanak.mealient.datasource.v1.models.VersionResponseV1 +import gq.kirmanak.mealient.datasource.v1.models.* import kotlinx.serialization.SerializationException import kotlinx.serialization.json.Json import retrofit2.HttpException @@ -26,10 +22,12 @@ class MealieDataSourceV1Impl @Inject constructor( override suspend fun addRecipe( baseUrl: String, token: String?, - recipe: AddRecipeRequestV0 - ): String { - TODO("Not yet implemented") - } + recipe: AddRecipeRequestV1 + ): String = networkRequestWrapper.makeCallAndHandleUnauthorized( + block = { service.addRecipe("$baseUrl/api/recipes/create", token, recipe) }, + logMethod = { "addRecipe" }, + logParameters = { "baseUrl = $baseUrl, token = $token, recipe = $recipe" } + ) override suspend fun authenticate( baseUrl: String, diff --git a/datasource/src/main/kotlin/gq/kirmanak/mealient/datasource/v1/MealieServiceV1.kt b/datasource/src/main/kotlin/gq/kirmanak/mealient/datasource/v1/MealieServiceV1.kt index e441396..6db2042 100644 --- a/datasource/src/main/kotlin/gq/kirmanak/mealient/datasource/v1/MealieServiceV1.kt +++ b/datasource/src/main/kotlin/gq/kirmanak/mealient/datasource/v1/MealieServiceV1.kt @@ -1,11 +1,7 @@ package gq.kirmanak.mealient.datasource.v1 import gq.kirmanak.mealient.datasource.DataSourceModule.Companion.AUTHORIZATION_HEADER_NAME -import gq.kirmanak.mealient.datasource.v0.models.AddRecipeRequestV0 -import gq.kirmanak.mealient.datasource.v1.models.GetRecipeResponseV1 -import gq.kirmanak.mealient.datasource.v1.models.GetRecipesResponseV1 -import gq.kirmanak.mealient.datasource.v1.models.GetTokenResponseV1 -import gq.kirmanak.mealient.datasource.v1.models.VersionResponseV1 +import gq.kirmanak.mealient.datasource.v1.models.* import retrofit2.http.* interface MealieServiceV1 { @@ -22,7 +18,7 @@ interface MealieServiceV1 { suspend fun addRecipe( @Url url: String, @Header(AUTHORIZATION_HEADER_NAME) token: String?, - @Body addRecipeRequestV0: AddRecipeRequestV0, + @Body addRecipeRequestV0: AddRecipeRequestV1, ): String @GET diff --git a/datasource/src/main/kotlin/gq/kirmanak/mealient/datasource/v1/models/AddRecipeRequestV1.kt b/datasource/src/main/kotlin/gq/kirmanak/mealient/datasource/v1/models/AddRecipeRequestV1.kt new file mode 100644 index 0000000..ffa23e1 --- /dev/null +++ b/datasource/src/main/kotlin/gq/kirmanak/mealient/datasource/v1/models/AddRecipeRequestV1.kt @@ -0,0 +1,54 @@ +package gq.kirmanak.mealient.datasource.v1.models + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class AddRecipeRequestV1( + @SerialName("name") val name: String = "", + @SerialName("description") val description: String = "", + @SerialName("image") val image: String = "", + @SerialName("recipeYield") val recipeYield: String = "", + @SerialName("recipeIngredient") val recipeIngredient: List = emptyList(), + @SerialName("recipeInstructions") val recipeInstructions: List = emptyList(), + @SerialName("slug") val slug: String = "", + @SerialName("filePath") val filePath: String = "", + @SerialName("tags") val tags: List = emptyList(), + @SerialName("categories") val categories: List = emptyList(), + @SerialName("notes") val notes: List = emptyList(), + @SerialName("extras") val extras: Map = emptyMap(), + @SerialName("assets") val assets: List = emptyList(), + @SerialName("settings") val settings: AddRecipeSettingsV1 = AddRecipeSettingsV1(), +) + +@Serializable +data class AddRecipeIngredientV1( + @SerialName("disableAmount") val disableAmount: Boolean = true, + @SerialName("food") val food: String? = null, + @SerialName("note") val note: String = "", + @SerialName("quantity") val quantity: Int = 1, + @SerialName("title") val title: String? = null, + @SerialName("unit") val unit: String? = null, +) + +@Serializable +data class AddRecipeInstructionV1( + @SerialName("title") val title: String = "", + @SerialName("text") val text: String = "", +) + +@Serializable +data class AddRecipeNoteV1( + @SerialName("title") val title: String = "", + @SerialName("text") val text: String = "", +) + +@Serializable +data class AddRecipeSettingsV1( + @SerialName("disableAmount") val disableAmount: Boolean = true, + @SerialName("disableComments") val disableComments: Boolean = false, + @SerialName("landscapeView") val landscapeView: Boolean = true, + @SerialName("public") val public: Boolean = true, + @SerialName("showAssets") val showAssets: Boolean = true, + @SerialName("showNutrition") val showNutrition: Boolean = true, +) \ No newline at end of file