Implement loading and saving full recipe info

This commit is contained in:
Kirill Kamakin
2021-11-17 20:44:14 +03:00
parent de6ca65b19
commit 7ebe89adfc
35 changed files with 355 additions and 39 deletions

View File

@@ -4,7 +4,8 @@ import androidx.room.Database
import androidx.room.RoomDatabase
import androidx.room.TypeConverters
import gq.kirmanak.mealie.data.impl.RoomTypeConverters
import gq.kirmanak.mealie.data.recipes.db.*
import gq.kirmanak.mealie.data.recipes.db.RecipeDao
import gq.kirmanak.mealie.data.recipes.db.entity.*
import javax.inject.Singleton
@Database(

View File

@@ -1,7 +1,7 @@
package gq.kirmanak.mealie.data.recipes
import androidx.paging.Pager
import gq.kirmanak.mealie.data.recipes.db.RecipeSummaryEntity
import gq.kirmanak.mealie.data.recipes.db.entity.RecipeSummaryEntity
interface RecipeRepo {
fun createPager(): Pager<Int, RecipeSummaryEntity>

View File

@@ -5,6 +5,7 @@ import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import gq.kirmanak.mealie.data.recipes.db.entity.*
@Dao
interface RecipeDao {
@@ -18,7 +19,7 @@ interface RecipeDao {
fun queryRecipesByPages(): PagingSource<Int, RecipeSummaryEntity>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertRecipe(recipeSummaryEntity: RecipeSummaryEntity): Long
suspend fun insertRecipe(recipeSummaryEntity: RecipeSummaryEntity)
@Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun insertTag(tagEntity: TagEntity): Long
@@ -55,4 +56,13 @@ interface RecipeDao {
@Query("SELECT * FROM tag_recipe")
suspend fun queryAllTagRecipes(): List<TagRecipeEntity>
@Insert
suspend fun insertRecipe(recipe: RecipeEntity)
@Insert
suspend fun insertRecipeInstructions(instructions: List<RecipeInstructionEntity>)
@Insert
suspend fun insertRecipeIngredients(ingredients: List<RecipeIngredientEntity>)
}

View File

@@ -1,7 +1,9 @@
package gq.kirmanak.mealie.data.recipes.db
import androidx.paging.PagingSource
import gq.kirmanak.mealie.data.recipes.network.GetRecipeSummaryResponse
import gq.kirmanak.mealie.data.recipes.db.entity.RecipeSummaryEntity
import gq.kirmanak.mealie.data.recipes.network.response.GetRecipeResponse
import gq.kirmanak.mealie.data.recipes.network.response.GetRecipeSummaryResponse
interface RecipeStorage {
suspend fun saveRecipes(recipes: List<GetRecipeSummaryResponse>)
@@ -11,4 +13,6 @@ interface RecipeStorage {
suspend fun refreshAll(recipes: List<GetRecipeSummaryResponse>)
suspend fun clearAllLocalData()
suspend fun saveRecipeInfo(recipe: GetRecipeResponse)
}

View File

@@ -3,7 +3,11 @@ package gq.kirmanak.mealie.data.recipes.db
import androidx.paging.PagingSource
import androidx.room.withTransaction
import gq.kirmanak.mealie.data.MealieDb
import gq.kirmanak.mealie.data.recipes.network.GetRecipeSummaryResponse
import gq.kirmanak.mealie.data.recipes.db.entity.*
import gq.kirmanak.mealie.data.recipes.network.response.GetRecipeIngredientResponse
import gq.kirmanak.mealie.data.recipes.network.response.GetRecipeInstructionResponse
import gq.kirmanak.mealie.data.recipes.network.response.GetRecipeResponse
import gq.kirmanak.mealie.data.recipes.network.response.GetRecipeSummaryResponse
import timber.log.Timber
import javax.inject.Inject
@@ -27,16 +31,20 @@ class RecipeStorageImpl @Inject constructor(
val categoryRecipeEntities = mutableSetOf<CategoryRecipeEntity>()
for (recipe in recipes) {
val recipeId = recipeDao.insertRecipe(recipe.recipeEntity())
val recipeSummaryEntity = recipe.recipeEntity()
recipeDao.insertRecipe(recipeSummaryEntity)
for (tag in recipe.tags) {
val tagId = getIdOrInsert(tagEntities, tag)
tagRecipeEntities += TagRecipeEntity(tagId, recipeId)
tagRecipeEntities += TagRecipeEntity(tagId, recipeSummaryEntity.remoteId)
}
for (category in recipe.recipeCategories) {
val categoryId = getOrInsert(categoryEntities, category)
categoryRecipeEntities += CategoryRecipeEntity(categoryId, recipeId)
categoryRecipeEntities += CategoryRecipeEntity(
categoryId,
recipeSummaryEntity.remoteId
)
}
}
@@ -108,4 +116,42 @@ class RecipeStorageImpl @Inject constructor(
recipeDao.removeAllTags()
}
}
override suspend fun saveRecipeInfo(recipe: GetRecipeResponse) {
Timber.v("saveRecipeInfo() called with: recipe = $recipe")
db.withTransaction {
recipeDao.insertRecipe(recipe.toRecipeEntity())
val ingredients = recipe.recipeIngredients.map {
it.toRecipeIngredientEntity(recipe.remoteId)
}
recipeDao.insertRecipeIngredients(ingredients)
val instructions = recipe.recipeInstructions.map {
it.toRecipeInstructionEntity(recipe.remoteId)
}
recipeDao.insertRecipeInstructions(instructions)
}
}
private fun GetRecipeResponse.toRecipeEntity() = RecipeEntity(
remoteId = remoteId,
recipeYield = recipeYield
)
private fun GetRecipeIngredientResponse.toRecipeIngredientEntity(remoteId: Long) =
RecipeIngredientEntity(
recipeId = remoteId,
title = title,
note = note,
unit = unit,
food = food,
disableAmount = disableAmount,
quantity = quantity
)
private fun GetRecipeInstructionResponse.toRecipeInstructionEntity(remoteId: Long) =
RecipeInstructionEntity(
recipeId = remoteId,
title = title,
text = text
)
}

View File

@@ -1,4 +1,4 @@
package gq.kirmanak.mealie.data.recipes.db
package gq.kirmanak.mealie.data.recipes.db.entity
import androidx.room.ColumnInfo
import androidx.room.Entity

View File

@@ -1,4 +1,4 @@
package gq.kirmanak.mealie.data.recipes.db
package gq.kirmanak.mealie.data.recipes.db.entity
import androidx.room.ColumnInfo
import androidx.room.Entity
@@ -17,7 +17,7 @@ import androidx.room.Index
onUpdate = ForeignKey.CASCADE
), ForeignKey(
entity = RecipeSummaryEntity::class,
parentColumns = ["local_id"],
parentColumns = ["remote_id"],
childColumns = ["recipe_id"],
onDelete = ForeignKey.CASCADE,
onUpdate = ForeignKey.CASCADE

View File

@@ -0,0 +1,11 @@
package gq.kirmanak.mealie.data.recipes.db.entity
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "recipe")
data class RecipeEntity(
@PrimaryKey @ColumnInfo(name = "remote_id") val remoteId: Long,
@ColumnInfo(name = "recipe_yield") val recipeYield: String,
)

View File

@@ -0,0 +1,16 @@
package gq.kirmanak.mealie.data.recipes.db.entity
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "recipe_ingredient")
data class RecipeIngredientEntity(
@PrimaryKey @ColumnInfo(name = "recipe_id") val recipeId: Long,
@ColumnInfo(name = "title") val title: String,
@ColumnInfo(name = "note") val note: String,
@ColumnInfo(name = "unit") val unit: String,
@ColumnInfo(name = "food") val food: String,
@ColumnInfo(name = "disable_amount") val disableAmount: Boolean,
@ColumnInfo(name = "quantity") val quantity: Int,
)

View File

@@ -0,0 +1,12 @@
package gq.kirmanak.mealie.data.recipes.db.entity
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "recipe_instruction")
data class RecipeInstructionEntity(
@PrimaryKey @ColumnInfo(name = "recipe_id") val recipeId: Long,
@ColumnInfo(name = "title") val title: String,
@ColumnInfo(name = "text") val text: String,
)

View File

@@ -1,16 +1,14 @@
package gq.kirmanak.mealie.data.recipes.db
package gq.kirmanak.mealie.data.recipes.db.entity
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.Index
import androidx.room.PrimaryKey
import kotlinx.datetime.LocalDate
import kotlinx.datetime.LocalDateTime
@Entity(tableName = "recipe_summaries", indices = [Index(value = ["remote_id"], unique = true)])
@Entity(tableName = "recipe_summaries")
data class RecipeSummaryEntity(
@PrimaryKey(autoGenerate = true) @ColumnInfo(name = "local_id") val localId: Long = 0,
@ColumnInfo(name = "remote_id") val remoteId: Long,
@PrimaryKey @ColumnInfo(name = "remote_id") val remoteId: Long,
@ColumnInfo(name = "name") val name: String,
@ColumnInfo(name = "slug") val slug: String,
@ColumnInfo(name = "image") val image: String,
@@ -20,6 +18,6 @@ data class RecipeSummaryEntity(
@ColumnInfo(name = "date_updated") val dateUpdated: LocalDateTime
) {
override fun toString(): String {
return "RecipeEntity(localId=$localId, remoteId=$remoteId, name='$name')"
return "RecipeEntity(remoteId=$remoteId, name='$name')"
}
}

View File

@@ -1,4 +1,4 @@
package gq.kirmanak.mealie.data.recipes.db
package gq.kirmanak.mealie.data.recipes.db.entity
import androidx.room.ColumnInfo
import androidx.room.Entity

View File

@@ -1,4 +1,4 @@
package gq.kirmanak.mealie.data.recipes.db
package gq.kirmanak.mealie.data.recipes.db.entity
import androidx.room.ColumnInfo
import androidx.room.Entity
@@ -15,7 +15,7 @@ import androidx.room.ForeignKey
onUpdate = ForeignKey.CASCADE
), ForeignKey(
entity = RecipeSummaryEntity::class,
parentColumns = ["local_id"],
parentColumns = ["remote_id"],
childColumns = ["recipe_id"],
onDelete = ForeignKey.CASCADE,
onUpdate = ForeignKey.CASCADE

View File

@@ -2,7 +2,7 @@ package gq.kirmanak.mealie.data.recipes.impl
import androidx.paging.PagingSource
import gq.kirmanak.mealie.data.recipes.db.RecipeStorage
import gq.kirmanak.mealie.data.recipes.db.RecipeSummaryEntity
import gq.kirmanak.mealie.data.recipes.db.entity.RecipeSummaryEntity
import timber.log.Timber
import javax.inject.Inject
import javax.inject.Singleton

View File

@@ -5,7 +5,7 @@ import androidx.paging.Pager
import androidx.paging.PagingConfig
import gq.kirmanak.mealie.data.recipes.RecipeRepo
import gq.kirmanak.mealie.data.recipes.db.RecipeStorage
import gq.kirmanak.mealie.data.recipes.db.RecipeSummaryEntity
import gq.kirmanak.mealie.data.recipes.db.entity.RecipeSummaryEntity
import timber.log.Timber
import javax.inject.Inject

View File

@@ -8,7 +8,7 @@ import androidx.paging.LoadType.REFRESH
import androidx.paging.PagingState
import androidx.paging.RemoteMediator
import gq.kirmanak.mealie.data.recipes.db.RecipeStorage
import gq.kirmanak.mealie.data.recipes.db.RecipeSummaryEntity
import gq.kirmanak.mealie.data.recipes.db.entity.RecipeSummaryEntity
import gq.kirmanak.mealie.data.recipes.network.RecipeDataSource
import kotlinx.coroutines.CancellationException
import timber.log.Timber

View File

@@ -1,5 +1,10 @@
package gq.kirmanak.mealie.data.recipes.network
import gq.kirmanak.mealie.data.recipes.network.response.GetRecipeResponse
import gq.kirmanak.mealie.data.recipes.network.response.GetRecipeSummaryResponse
interface RecipeDataSource {
suspend fun requestRecipes(start: Int = 0, limit: Int = 9999): List<GetRecipeSummaryResponse>
suspend fun requestRecipeInfo(slug: String): GetRecipeResponse
}

View File

@@ -2,6 +2,8 @@ package gq.kirmanak.mealie.data.recipes.network
import gq.kirmanak.mealie.data.auth.AuthRepo
import gq.kirmanak.mealie.data.impl.RetrofitBuilder
import gq.kirmanak.mealie.data.recipes.network.response.GetRecipeResponse
import gq.kirmanak.mealie.data.recipes.network.response.GetRecipeSummaryResponse
import kotlinx.serialization.ExperimentalSerializationApi
import timber.log.Timber
import javax.inject.Inject
@@ -21,6 +23,14 @@ class RecipeDataSourceImpl @Inject constructor(
return recipeSummary
}
override suspend fun requestRecipeInfo(slug: String): GetRecipeResponse {
Timber.v("requestRecipeInfo() called with: slug = $slug")
val service: RecipeService = getRecipeService()
val recipeInfo = service.getRecipe(slug)
Timber.v("requestRecipeInfo() returned: $recipeInfo")
return recipeInfo
}
private suspend fun getRecipeService(): RecipeService {
Timber.v("getRecipeService() called")
val cachedService: RecipeService? = _recipeService

View File

@@ -1,6 +1,9 @@
package gq.kirmanak.mealie.data.recipes.network
import gq.kirmanak.mealie.data.recipes.network.response.GetRecipeResponse
import gq.kirmanak.mealie.data.recipes.network.response.GetRecipeSummaryResponse
import retrofit2.http.GET
import retrofit2.http.Path
import retrofit2.http.Query
interface RecipeService {
@@ -9,4 +12,9 @@ interface RecipeService {
@Query("start") start: Int,
@Query("limit") limit: Int
): List<GetRecipeSummaryResponse>
@GET("/api/recipes/:recipe_slug")
suspend fun getRecipe(
@Path("recipe_slug") recipeSlug: String
): GetRecipeResponse
}

View File

@@ -0,0 +1,14 @@
package gq.kirmanak.mealie.data.recipes.network.response
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class GetRecipeIngredientResponse(
@SerialName("title") val title: String = "",
@SerialName("note") val note: String = "",
@SerialName("unit") val unit: String = "",
@SerialName("food") val food: String = "",
@SerialName("disableAmount") val disableAmount: Boolean,
@SerialName("quantity") val quantity: Int,
)

View File

@@ -0,0 +1,10 @@
package gq.kirmanak.mealie.data.recipes.network.response
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class GetRecipeInstructionResponse(
@SerialName("title") val title: String = "",
@SerialName("text") val text: String,
)

View File

@@ -0,0 +1,23 @@
package gq.kirmanak.mealie.data.recipes.network.response
import kotlinx.datetime.LocalDate
import kotlinx.datetime.LocalDateTime
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class GetRecipeResponse(
@SerialName("id") val remoteId: Long,
@SerialName("name") val name: String,
@SerialName("slug") val slug: String,
@SerialName("image") val image: String,
@SerialName("description") val description: String = "",
@SerialName("recipeCategory") val recipeCategories: List<String>,
@SerialName("tags") val tags: List<String>,
@SerialName("rating") val rating: Int?,
@SerialName("dateAdded") val dateAdded: LocalDate,
@SerialName("dateUpdated") val dateUpdated: LocalDateTime,
@SerialName("recipeYield") val recipeYield: String = "",
@SerialName("recipeIngredient") val recipeIngredients: List<GetRecipeIngredientResponse>,
@SerialName("recipeInstructions") val recipeInstructions: List<GetRecipeInstructionResponse>,
)

View File

@@ -1,4 +1,4 @@
package gq.kirmanak.mealie.data.recipes.network
package gq.kirmanak.mealie.data.recipes.network.response
import kotlinx.datetime.LocalDate
import kotlinx.datetime.LocalDateTime

View File

@@ -2,7 +2,7 @@ package gq.kirmanak.mealie.ui.recipes
import androidx.recyclerview.widget.RecyclerView
import gq.kirmanak.mealie.R
import gq.kirmanak.mealie.data.recipes.db.RecipeSummaryEntity
import gq.kirmanak.mealie.data.recipes.db.entity.RecipeSummaryEntity
import gq.kirmanak.mealie.databinding.ViewHolderRecipeBinding
class RecipeViewHolder(

View File

@@ -6,7 +6,7 @@ import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import gq.kirmanak.mealie.data.recipes.RecipeImageLoader
import gq.kirmanak.mealie.data.recipes.RecipeRepo
import gq.kirmanak.mealie.data.recipes.db.RecipeSummaryEntity
import gq.kirmanak.mealie.data.recipes.db.entity.RecipeSummaryEntity
import kotlinx.coroutines.launch
import javax.inject.Inject

View File

@@ -4,7 +4,7 @@ import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.paging.PagingDataAdapter
import androidx.recyclerview.widget.DiffUtil
import gq.kirmanak.mealie.data.recipes.db.RecipeSummaryEntity
import gq.kirmanak.mealie.data.recipes.db.entity.RecipeSummaryEntity
import gq.kirmanak.mealie.databinding.ViewHolderRecipeBinding
import timber.log.Timber

View File

@@ -0,0 +1,8 @@
package gq.kirmanak.mealie.ui.recipes.info
import androidx.fragment.app.Fragment
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class RecipeInfoFragment : Fragment() {
}

View File

@@ -0,0 +1,89 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/image"
android:layout_width="0dp"
android:layout_height="@dimen/fragment_recipe_info_image_height"
android:layout_marginBottom="@dimen/margin_small"
android:contentDescription="@string/content_description_fragment_recipe_info_image"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:srcCompat="@tools:sample/backgrounds/scenic" />
<TextView
android:id="@+id/title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="@dimen/margin_small"
android:textAppearance="?textAppearanceHeadline6"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/image"
tools:text="Best-Ever Beef Stew" />
<TextView
android:id="@+id/description"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="@dimen/margin_small"
android:textAppearance="?textAppearanceBody2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/title"
tools:text="Stay warm all winter with this classic Beef Stew made with red wine and beef stock from Delish.com." />
<TextView
android:id="@+id/ingredients_header"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="@dimen/margin_small"
android:text="@string/fragment_recipe_info_ingredients_header"
android:textAppearance="?textAppearanceHeadline6"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/description" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/ingredients_list"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="@dimen/margin_small"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/ingredients_header"
tools:itemCount="3"
tools:listitem="@layout/view_holder_ingredient" />
<TextView
android:id="@+id/instructions_header"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="@dimen/margin_small"
android:text="@string/fragment_recipe_info_instructions_header"
android:textAppearance="?textAppearanceHeadline6"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/ingredients_list" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/instructions_list"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="@dimen/margin_small"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/instructions_header"
tools:itemCount="2"
tools:listitem="@layout/view_holder_instruction" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<CheckBox
android:id="@+id/checkBox"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="@dimen/margin_small"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="900 g braising steak/stew meat, cubed into 2.5cm pieces" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/step"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="@dimen/margin_small"
android:textAppearance="?textAppearanceHeadline6"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Step: 1" />
<TextView
android:id="@+id/instruction"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="@dimen/margin_small"
android:textAppearance="?textAppearanceBody2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/step"
tools:text="In a large dutch oven or heavy-bottomed pot over medium heat, heat oil. Add beef and cook until seared on all sides, 10 minutes, working in batches if necessary. Transfer beef to a plate." />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -3,4 +3,5 @@
<dimen name="margin_small">8dp</dimen>
<dimen name="width_view_holder_recipe_image">360dp</dimen>
<dimen name="height_view_holder_recipe_image">180dp</dimen>
<dimen name="fragment_recipe_info_image_height">@dimen/height_view_holder_recipe_image</dimen>
</resources>

View File

@@ -8,4 +8,7 @@
<string name="menu_main_toolbar_content_description_logout">@string/menu_main_toolbar_logout</string>
<string name="menu_main_toolbar_logout">Logout</string>
<string name="view_holder_recipe_text_placeholder">Loading…</string>
<string name="content_description_fragment_recipe_info_image">@string/content_description_view_holder_recipe_image</string>
<string name="fragment_recipe_info_ingredients_header">Ingredients</string>
<string name="fragment_recipe_info_instructions_header">Instructions</string>
</resources>

View File

@@ -1,7 +1,7 @@
package gq.kirmanak.mealie.data.recipes
import gq.kirmanak.mealie.data.recipes.db.RecipeSummaryEntity
import gq.kirmanak.mealie.data.recipes.network.GetRecipeSummaryResponse
import gq.kirmanak.mealie.data.recipes.db.entity.RecipeSummaryEntity
import gq.kirmanak.mealie.data.recipes.network.response.GetRecipeSummaryResponse
import kotlinx.datetime.LocalDate
import kotlinx.datetime.LocalDateTime
import okhttp3.mockwebserver.MockResponse
@@ -68,7 +68,6 @@ object RecipeImplTestData {
"""
val CAKE_RECIPE_ENTITY = RecipeSummaryEntity(
localId = 1,
remoteId = 1,
name = "Cake",
slug = "cake",
@@ -80,7 +79,6 @@ object RecipeImplTestData {
)
val PORRIDGE_RECIPE_ENTITY = RecipeSummaryEntity(
localId = 2,
remoteId = 2,
name = "Porridge",
slug = "porridge",

View File

@@ -8,6 +8,10 @@ import gq.kirmanak.mealie.data.recipes.RecipeImplTestData.CAKE_RECIPE_ENTITY
import gq.kirmanak.mealie.data.recipes.RecipeImplTestData.PORRIDGE_RECIPE_ENTITY
import gq.kirmanak.mealie.data.recipes.RecipeImplTestData.RECIPE_SUMMARY_CAKE
import gq.kirmanak.mealie.data.recipes.RecipeImplTestData.TEST_RECIPE_SUMMARIES
import gq.kirmanak.mealie.data.recipes.db.entity.CategoryEntity
import gq.kirmanak.mealie.data.recipes.db.entity.CategoryRecipeEntity
import gq.kirmanak.mealie.data.recipes.db.entity.TagEntity
import gq.kirmanak.mealie.data.recipes.db.entity.TagRecipeEntity
import kotlinx.coroutines.runBlocking
import org.junit.Test
import javax.inject.Inject
@@ -79,9 +83,7 @@ class RecipeStorageImplTest : HiltRobolectricTest() {
subject.saveRecipes(TEST_RECIPE_SUMMARIES)
subject.refreshAll(listOf(RECIPE_SUMMARY_CAKE))
val actual = mealieDb.recipeDao().queryAllRecipes()
assertThat(actual).containsExactly(
CAKE_RECIPE_ENTITY.copy(localId = 3),
)
assertThat(actual).containsExactly(CAKE_RECIPE_ENTITY)
}
@Test
@@ -90,8 +92,8 @@ class RecipeStorageImplTest : HiltRobolectricTest() {
subject.refreshAll(listOf(RECIPE_SUMMARY_CAKE))
val actual = mealieDb.recipeDao().queryAllCategoryRecipes()
assertThat(actual).containsExactly(
CategoryRecipeEntity(categoryId = 1, recipeId = 3),
CategoryRecipeEntity(categoryId = 2, recipeId = 3),
CategoryRecipeEntity(categoryId = 1, recipeId = 1),
CategoryRecipeEntity(categoryId = 2, recipeId = 1),
)
}
@@ -101,8 +103,8 @@ class RecipeStorageImplTest : HiltRobolectricTest() {
subject.refreshAll(listOf(RECIPE_SUMMARY_CAKE))
val actual = mealieDb.recipeDao().queryAllTagRecipes()
assertThat(actual).containsExactly(
TagRecipeEntity(tagId = 1, recipeId = 3),
TagRecipeEntity(tagId = 2, recipeId = 3),
TagRecipeEntity(tagId = 1, recipeId = 1),
TagRecipeEntity(tagId = 2, recipeId = 1),
)
}

View File

@@ -15,7 +15,7 @@ import gq.kirmanak.mealie.data.recipes.RecipeImplTestData.PORRIDGE_RECIPE_ENTITY
import gq.kirmanak.mealie.data.recipes.RecipeImplTestData.TEST_RECIPE_ENTITIES
import gq.kirmanak.mealie.data.recipes.RecipeImplTestData.enqueueSuccessfulRecipeSummaryResponse
import gq.kirmanak.mealie.data.recipes.RecipeImplTestData.enqueueUnsuccessfulRecipeSummaryResponse
import gq.kirmanak.mealie.data.recipes.db.RecipeSummaryEntity
import gq.kirmanak.mealie.data.recipes.db.entity.RecipeSummaryEntity
import kotlinx.coroutines.runBlocking
import org.junit.Before
import org.junit.Test