Implement shopping lists screen (#129)
* Initialize shopping lists feature * Start shopping lists screen with Compose * Add icon to shopping list name * Add shopping lists to menu * Set max size for the list * Replace compose-adapter with accompanist * Remove unused fields from shopping lists response * Show list of shopping lists from BE * Hide shopping lists if Mealie is 0.5.6 * Add shopping list item click listener * Create material app theme for Compose * Use shorter names * Load shopping lists by pages and save to db * Make page handling logic match recipes * Add swipe to refresh to shopping lists * Extract SwipeToRefresh Composable * Make LazyPagingColumn generic * Show refresh only when mediator is refreshing * Do not refresh automatically * Allow controlling Activity state from modules * Implement navigating to shopping list screen * Move Compose libraries setup to a plugin * Implement loading full shopping list info * Move Storage classes to database module * Save shopping list items to DB * Use separate names for separate ids * Do only one DB version update * Use unique names for all columns * Display shopping list items * Move OperationUiState to ui module * Subscribe to shopping lists updates * Indicate progress with progress bar * Use strings from resources * Format shopping list item quantities * Hide unit/food/note/quantity if they are not set * Implement updating shopping list item checked state * Remove unnecessary null checks * Disable checkbox when it is being updated * Split shopping list screen into composables * Show items immediately if they are saved * Fix showing "list is empty" before the items * Show Snackbar when error happens * Reduce shopping list items paddings * Remove shopping lists when URL is changed * Add error/empty state handling to shopping lists * Fix empty error state * Fix tests compilation * Add margin between text and button * Add divider between checked and unchecked items * Move divider to the item * Refresh the shopping lists on authentication * Use retry when necessary * Remove excessive logging * Fix pages bounds check * Move FlowExtensionsTest * Update Compose version * Fix showing loading indicator for shopping lists * Add Russian translation * Fix SDK version lint check * Rename parameter to match interface * Add DB migration TODO * Get rid of DB migrations * Do not use pagination with shopping lists * Cleanup after the pagination removal * Load shopping list items * Remove shopping lists storage * Rethrow CancellationException in LoadingHelper * Add pull-to-refresh on shopping list screen * Extract LazyColumnWithLoadingState * Split refresh errors and loading state * Reuse LazyColumnWithLoadingState for shopping list items * Remove paging-compose dependency * Refresh shopping list items on authentication * Disable missing translation lint check * Update Compose and Kotlin versions * Fix order of checked items * Hide useless information from a shopping list item
This commit is contained in:
@@ -80,9 +80,15 @@ dependencies {
|
|||||||
|
|
||||||
implementation(project(":architecture"))
|
implementation(project(":architecture"))
|
||||||
implementation(project(":database"))
|
implementation(project(":database"))
|
||||||
|
testImplementation(project(":database_test"))
|
||||||
implementation(project(":datastore"))
|
implementation(project(":datastore"))
|
||||||
|
testImplementation(project(":datastore_test"))
|
||||||
implementation(project(":datasource"))
|
implementation(project(":datasource"))
|
||||||
|
testImplementation(project(":datasource_test"))
|
||||||
implementation(project(":logging"))
|
implementation(project(":logging"))
|
||||||
|
implementation(project(":ui"))
|
||||||
|
implementation(project(":features:shopping_lists"))
|
||||||
|
implementation(project(":model_mapper"))
|
||||||
testImplementation(project(":testing"))
|
testImplementation(project(":testing"))
|
||||||
|
|
||||||
implementation(libs.android.material.material)
|
implementation(libs.android.material.material)
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package gq.kirmanak.mealient.data.add
|
package gq.kirmanak.mealient.data.add
|
||||||
|
|
||||||
|
import gq.kirmanak.mealient.datasource.models.AddRecipeInfo
|
||||||
|
|
||||||
interface AddRecipeDataSource {
|
interface AddRecipeDataSource {
|
||||||
|
|
||||||
suspend fun addRecipe(recipe: AddRecipeInfo): String
|
suspend fun addRecipe(recipe: AddRecipeInfo): String
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package gq.kirmanak.mealient.data.add
|
package gq.kirmanak.mealient.data.add
|
||||||
|
|
||||||
|
import gq.kirmanak.mealient.datasource.models.AddRecipeInfo
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
interface AddRecipeRepo {
|
interface AddRecipeRepo {
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
package gq.kirmanak.mealient.data.add.impl
|
package gq.kirmanak.mealient.data.add.impl
|
||||||
|
|
||||||
import gq.kirmanak.mealient.data.add.AddRecipeDataSource
|
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.data.add.AddRecipeRepo
|
||||||
|
import gq.kirmanak.mealient.datasource.models.AddRecipeInfo
|
||||||
import gq.kirmanak.mealient.datastore.recipe.AddRecipeStorage
|
import gq.kirmanak.mealient.datastore.recipe.AddRecipeStorage
|
||||||
import gq.kirmanak.mealient.extensions.toAddRecipeInfo
|
|
||||||
import gq.kirmanak.mealient.extensions.toDraft
|
|
||||||
import gq.kirmanak.mealient.logging.Logger
|
import gq.kirmanak.mealient.logging.Logger
|
||||||
|
import gq.kirmanak.mealient.model_mapper.ModelMapper
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
@@ -18,14 +17,15 @@ class AddRecipeRepoImpl @Inject constructor(
|
|||||||
private val addRecipeDataSource: AddRecipeDataSource,
|
private val addRecipeDataSource: AddRecipeDataSource,
|
||||||
private val addRecipeStorage: AddRecipeStorage,
|
private val addRecipeStorage: AddRecipeStorage,
|
||||||
private val logger: Logger,
|
private val logger: Logger,
|
||||||
|
private val modelMapper: ModelMapper,
|
||||||
) : AddRecipeRepo {
|
) : AddRecipeRepo {
|
||||||
|
|
||||||
override val addRecipeRequestFlow: Flow<AddRecipeInfo>
|
override val addRecipeRequestFlow: Flow<AddRecipeInfo>
|
||||||
get() = addRecipeStorage.updates.map { it.toAddRecipeInfo() }
|
get() = addRecipeStorage.updates.map { modelMapper.toAddRecipeInfo(it) }
|
||||||
|
|
||||||
override suspend fun preserve(recipe: AddRecipeInfo) {
|
override suspend fun preserve(recipe: AddRecipeInfo) {
|
||||||
logger.v { "preserveRecipe() called with: recipe = $recipe" }
|
logger.v { "preserveRecipe() called with: recipe = $recipe" }
|
||||||
addRecipeStorage.save(recipe.toDraft())
|
addRecipeStorage.save(modelMapper.toDraft(recipe))
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun clear() {
|
override suspend fun clear() {
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
package gq.kirmanak.mealient.data.auth
|
package gq.kirmanak.mealient.data.auth
|
||||||
|
|
||||||
|
import gq.kirmanak.mealient.shopping_lists.repo.ShoppingListsAuthRepo
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
interface AuthRepo {
|
interface AuthRepo : ShoppingListsAuthRepo {
|
||||||
|
|
||||||
val isAuthorizedFlow: Flow<Boolean>
|
override val isAuthorizedFlow: Flow<Boolean>
|
||||||
|
|
||||||
suspend fun authenticate(email: String, password: String)
|
suspend fun authenticate(email: String, password: String)
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package gq.kirmanak.mealient.data.baseurl
|
package gq.kirmanak.mealient.data.baseurl
|
||||||
|
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
interface ServerInfoRepo {
|
interface ServerInfoRepo {
|
||||||
|
|
||||||
suspend fun getUrl(): String?
|
suspend fun getUrl(): String?
|
||||||
@@ -8,5 +10,7 @@ interface ServerInfoRepo {
|
|||||||
|
|
||||||
suspend fun tryBaseURL(baseURL: String): Result<Unit>
|
suspend fun tryBaseURL(baseURL: String): Result<Unit>
|
||||||
|
|
||||||
|
fun versionUpdates(): Flow<ServerVersion>
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,9 @@ package gq.kirmanak.mealient.data.baseurl
|
|||||||
import gq.kirmanak.mealient.datasource.ServerUrlProvider
|
import gq.kirmanak.mealient.datasource.ServerUrlProvider
|
||||||
import gq.kirmanak.mealient.datasource.runCatchingExceptCancel
|
import gq.kirmanak.mealient.datasource.runCatchingExceptCancel
|
||||||
import gq.kirmanak.mealient.logging.Logger
|
import gq.kirmanak.mealient.logging.Logger
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.filterNotNull
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@@ -55,4 +58,11 @@ class ServerInfoRepoImpl @Inject constructor(
|
|||||||
serverInfoStorage.storeBaseURL(oldBaseUrl, oldVersion)
|
serverInfoStorage.storeBaseURL(oldBaseUrl, oldVersion)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun versionUpdates(): Flow<ServerVersion> {
|
||||||
|
return serverInfoStorage
|
||||||
|
.serverVersionUpdates()
|
||||||
|
.filterNotNull()
|
||||||
|
.map { determineServerVersion(it) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
package gq.kirmanak.mealient.data.baseurl
|
package gq.kirmanak.mealient.data.baseurl
|
||||||
|
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
interface ServerInfoStorage {
|
interface ServerInfoStorage {
|
||||||
|
|
||||||
suspend fun getBaseURL(): String?
|
suspend fun getBaseURL(): String?
|
||||||
@@ -12,4 +14,5 @@ interface ServerInfoStorage {
|
|||||||
|
|
||||||
suspend fun getServerVersion(): String?
|
suspend fun getServerVersion(): String?
|
||||||
|
|
||||||
|
fun serverVersionUpdates(): Flow<String?>
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
package gq.kirmanak.mealient.data.baseurl
|
package gq.kirmanak.mealient.data.baseurl
|
||||||
|
|
||||||
|
import gq.kirmanak.mealient.datasource.models.VersionInfo
|
||||||
|
|
||||||
interface VersionDataSource {
|
interface VersionDataSource {
|
||||||
|
|
||||||
suspend fun getVersionInfo(): VersionInfo
|
suspend fun getVersionInfo(): VersionInfo
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
package gq.kirmanak.mealient.data.baseurl
|
package gq.kirmanak.mealient.data.baseurl
|
||||||
|
|
||||||
|
import gq.kirmanak.mealient.datasource.models.VersionInfo
|
||||||
import gq.kirmanak.mealient.datasource.runCatchingExceptCancel
|
import gq.kirmanak.mealient.datasource.runCatchingExceptCancel
|
||||||
import gq.kirmanak.mealient.datasource.v0.MealieDataSourceV0
|
import gq.kirmanak.mealient.datasource.v0.MealieDataSourceV0
|
||||||
import gq.kirmanak.mealient.datasource.v1.MealieDataSourceV1
|
import gq.kirmanak.mealient.datasource.v1.MealieDataSourceV1
|
||||||
import gq.kirmanak.mealient.extensions.toVersionInfo
|
import gq.kirmanak.mealient.model_mapper.ModelMapper
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.awaitAll
|
import kotlinx.coroutines.awaitAll
|
||||||
import kotlinx.coroutines.coroutineScope
|
import kotlinx.coroutines.coroutineScope
|
||||||
@@ -14,15 +15,16 @@ import javax.inject.Singleton
|
|||||||
class VersionDataSourceImpl @Inject constructor(
|
class VersionDataSourceImpl @Inject constructor(
|
||||||
private val v0Source: MealieDataSourceV0,
|
private val v0Source: MealieDataSourceV0,
|
||||||
private val v1Source: MealieDataSourceV1,
|
private val v1Source: MealieDataSourceV1,
|
||||||
|
private val modelMapper: ModelMapper,
|
||||||
) : VersionDataSource {
|
) : VersionDataSource {
|
||||||
|
|
||||||
override suspend fun getVersionInfo(): VersionInfo {
|
override suspend fun getVersionInfo(): VersionInfo {
|
||||||
val responses = coroutineScope {
|
val responses = coroutineScope {
|
||||||
val v0Deferred = async {
|
val v0Deferred = async {
|
||||||
runCatchingExceptCancel { v0Source.getVersionInfo().toVersionInfo() }
|
runCatchingExceptCancel { modelMapper.toVersionInfo(v0Source.getVersionInfo()) }
|
||||||
}
|
}
|
||||||
val v1Deferred = async {
|
val v1Deferred = async {
|
||||||
runCatchingExceptCancel { v1Source.getVersionInfo().toVersionInfo() }
|
runCatchingExceptCancel { modelMapper.toVersionInfo(v1Source.getVersionInfo()) }
|
||||||
}
|
}
|
||||||
listOf(v0Deferred, v1Deferred).awaitAll()
|
listOf(v0Deferred, v1Deferred).awaitAll()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package gq.kirmanak.mealient.data.baseurl.impl
|
|||||||
import androidx.datastore.preferences.core.Preferences
|
import androidx.datastore.preferences.core.Preferences
|
||||||
import gq.kirmanak.mealient.data.baseurl.ServerInfoStorage
|
import gq.kirmanak.mealient.data.baseurl.ServerInfoStorage
|
||||||
import gq.kirmanak.mealient.data.storage.PreferencesStorage
|
import gq.kirmanak.mealient.data.storage.PreferencesStorage
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@@ -49,6 +50,10 @@ class ServerInfoStorageImpl @Inject constructor(
|
|||||||
preferencesStorage.storeValues(Pair(serverVersionKey, version))
|
preferencesStorage.storeValues(Pair(serverVersionKey, version))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun serverVersionUpdates(): Flow<String?> {
|
||||||
|
return preferencesStorage.valueUpdates(serverVersionKey)
|
||||||
|
}
|
||||||
|
|
||||||
private suspend fun <T> getValue(key: Preferences.Key<T>): T? = preferencesStorage.getValue(key)
|
private suspend fun <T> getValue(key: Preferences.Key<T>): T? = preferencesStorage.getValue(key)
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,22 +1,17 @@
|
|||||||
package gq.kirmanak.mealient.data.network
|
package gq.kirmanak.mealient.data.network
|
||||||
|
|
||||||
import gq.kirmanak.mealient.data.add.AddRecipeDataSource
|
import gq.kirmanak.mealient.data.add.AddRecipeDataSource
|
||||||
import gq.kirmanak.mealient.data.add.AddRecipeInfo
|
|
||||||
import gq.kirmanak.mealient.data.baseurl.ServerInfoRepo
|
import gq.kirmanak.mealient.data.baseurl.ServerInfoRepo
|
||||||
import gq.kirmanak.mealient.data.baseurl.ServerVersion
|
import gq.kirmanak.mealient.data.baseurl.ServerVersion
|
||||||
import gq.kirmanak.mealient.data.recipes.network.FullRecipeInfo
|
|
||||||
import gq.kirmanak.mealient.data.recipes.network.RecipeDataSource
|
import gq.kirmanak.mealient.data.recipes.network.RecipeDataSource
|
||||||
import gq.kirmanak.mealient.data.recipes.network.RecipeSummaryInfo
|
|
||||||
import gq.kirmanak.mealient.data.share.ParseRecipeDataSource
|
import gq.kirmanak.mealient.data.share.ParseRecipeDataSource
|
||||||
import gq.kirmanak.mealient.data.share.ParseRecipeURLInfo
|
import gq.kirmanak.mealient.datasource.models.AddRecipeInfo
|
||||||
|
import gq.kirmanak.mealient.datasource.models.FullRecipeInfo
|
||||||
|
import gq.kirmanak.mealient.datasource.models.ParseRecipeURLInfo
|
||||||
|
import gq.kirmanak.mealient.datasource.models.RecipeSummaryInfo
|
||||||
import gq.kirmanak.mealient.datasource.v0.MealieDataSourceV0
|
import gq.kirmanak.mealient.datasource.v0.MealieDataSourceV0
|
||||||
import gq.kirmanak.mealient.datasource.v1.MealieDataSourceV1
|
import gq.kirmanak.mealient.datasource.v1.MealieDataSourceV1
|
||||||
import gq.kirmanak.mealient.extensions.toFullRecipeInfo
|
import gq.kirmanak.mealient.model_mapper.ModelMapper
|
||||||
import gq.kirmanak.mealient.extensions.toRecipeSummaryInfo
|
|
||||||
import gq.kirmanak.mealient.extensions.toV0Request
|
|
||||||
import gq.kirmanak.mealient.extensions.toV1CreateRequest
|
|
||||||
import gq.kirmanak.mealient.extensions.toV1Request
|
|
||||||
import gq.kirmanak.mealient.extensions.toV1UpdateRequest
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@@ -25,15 +20,16 @@ class MealieDataSourceWrapper @Inject constructor(
|
|||||||
private val serverInfoRepo: ServerInfoRepo,
|
private val serverInfoRepo: ServerInfoRepo,
|
||||||
private val v0Source: MealieDataSourceV0,
|
private val v0Source: MealieDataSourceV0,
|
||||||
private val v1Source: MealieDataSourceV1,
|
private val v1Source: MealieDataSourceV1,
|
||||||
|
private val modelMapper: ModelMapper,
|
||||||
) : AddRecipeDataSource, RecipeDataSource, ParseRecipeDataSource {
|
) : AddRecipeDataSource, RecipeDataSource, ParseRecipeDataSource {
|
||||||
|
|
||||||
private suspend fun getVersion(): ServerVersion = serverInfoRepo.getVersion()
|
private suspend fun getVersion(): ServerVersion = serverInfoRepo.getVersion()
|
||||||
|
|
||||||
override suspend fun addRecipe(recipe: AddRecipeInfo): String = when (getVersion()) {
|
override suspend fun addRecipe(recipe: AddRecipeInfo): String = when (getVersion()) {
|
||||||
ServerVersion.V0 -> v0Source.addRecipe(recipe.toV0Request())
|
ServerVersion.V0 -> v0Source.addRecipe(modelMapper.toV0Request(recipe))
|
||||||
ServerVersion.V1 -> {
|
ServerVersion.V1 -> {
|
||||||
val slug = v1Source.createRecipe(recipe.toV1CreateRequest())
|
val slug = v1Source.createRecipe(modelMapper.toV1CreateRequest(recipe))
|
||||||
v1Source.updateRecipe(slug, recipe.toV1UpdateRequest())
|
v1Source.updateRecipe(slug, modelMapper.toV1UpdateRequest(recipe))
|
||||||
slug
|
slug
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -43,25 +39,25 @@ class MealieDataSourceWrapper @Inject constructor(
|
|||||||
limit: Int,
|
limit: Int,
|
||||||
): List<RecipeSummaryInfo> = when (getVersion()) {
|
): List<RecipeSummaryInfo> = when (getVersion()) {
|
||||||
ServerVersion.V0 -> {
|
ServerVersion.V0 -> {
|
||||||
v0Source.requestRecipes(start, limit).map { it.toRecipeSummaryInfo() }
|
v0Source.requestRecipes(start, limit).map { modelMapper.toRecipeSummaryInfo(it) }
|
||||||
}
|
}
|
||||||
ServerVersion.V1 -> {
|
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
|
// Imagine start is 30 and limit is 15. It means that we already have page 1 and 2, now we need page 3
|
||||||
val page = start / limit + 1
|
val page = start / limit + 1
|
||||||
v1Source.requestRecipes(page, limit).map { it.toRecipeSummaryInfo() }
|
v1Source.requestRecipes(page, limit).map { modelMapper.toRecipeSummaryInfo(it) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun requestRecipeInfo(slug: String): FullRecipeInfo = when (getVersion()) {
|
override suspend fun requestRecipeInfo(slug: String): FullRecipeInfo = when (getVersion()) {
|
||||||
ServerVersion.V0 -> v0Source.requestRecipeInfo(slug).toFullRecipeInfo()
|
ServerVersion.V0 -> modelMapper.toFullRecipeInfo(v0Source.requestRecipeInfo(slug))
|
||||||
ServerVersion.V1 -> v1Source.requestRecipeInfo(slug).toFullRecipeInfo()
|
ServerVersion.V1 -> modelMapper.toFullRecipeInfo(v1Source.requestRecipeInfo(slug))
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun parseRecipeFromURL(
|
override suspend fun parseRecipeFromURL(
|
||||||
parseRecipeURLInfo: ParseRecipeURLInfo,
|
parseRecipeURLInfo: ParseRecipeURLInfo,
|
||||||
): String = when (getVersion()) {
|
): String = when (getVersion()) {
|
||||||
ServerVersion.V0 -> v0Source.parseRecipeFromURL(parseRecipeURLInfo.toV0Request())
|
ServerVersion.V0 -> v0Source.parseRecipeFromURL(modelMapper.toV0Request(parseRecipeURLInfo))
|
||||||
ServerVersion.V1 -> v1Source.parseRecipeFromURL(parseRecipeURLInfo.toV1Request())
|
ServerVersion.V1 -> v1Source.parseRecipeFromURL(modelMapper.toV1Request(parseRecipeURLInfo))
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getFavoriteRecipes(): List<String> = when (getVersion()) {
|
override suspend fun getFavoriteRecipes(): List<String> = when (getVersion()) {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package gq.kirmanak.mealient.data.recipes
|
package gq.kirmanak.mealient.data.recipes
|
||||||
|
|
||||||
import androidx.paging.Pager
|
import androidx.paging.Pager
|
||||||
import gq.kirmanak.mealient.database.recipe.entity.FullRecipeEntity
|
|
||||||
import gq.kirmanak.mealient.database.recipe.entity.RecipeSummaryEntity
|
import gq.kirmanak.mealient.database.recipe.entity.RecipeSummaryEntity
|
||||||
|
import gq.kirmanak.mealient.database.recipe.entity.RecipeWithSummaryAndIngredientsAndInstructions
|
||||||
|
|
||||||
interface RecipeRepo {
|
interface RecipeRepo {
|
||||||
|
|
||||||
@@ -12,7 +12,7 @@ interface RecipeRepo {
|
|||||||
|
|
||||||
suspend fun refreshRecipeInfo(recipeSlug: String): Result<Unit>
|
suspend fun refreshRecipeInfo(recipeSlug: String): Result<Unit>
|
||||||
|
|
||||||
suspend fun loadRecipeInfo(recipeId: String): FullRecipeEntity?
|
suspend fun loadRecipeInfo(recipeId: String): RecipeWithSummaryAndIngredientsAndInstructions?
|
||||||
|
|
||||||
fun updateNameQuery(name: String?)
|
fun updateNameQuery(name: String?)
|
||||||
|
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
package gq.kirmanak.mealient.data.recipes.db
|
|
||||||
|
|
||||||
import androidx.paging.PagingSource
|
|
||||||
import gq.kirmanak.mealient.data.recipes.network.FullRecipeInfo
|
|
||||||
import gq.kirmanak.mealient.database.recipe.entity.FullRecipeEntity
|
|
||||||
import gq.kirmanak.mealient.database.recipe.entity.RecipeSummaryEntity
|
|
||||||
|
|
||||||
interface RecipeStorage {
|
|
||||||
suspend fun saveRecipes(recipes: List<RecipeSummaryEntity>)
|
|
||||||
|
|
||||||
fun queryRecipes(query: String?): PagingSource<Int, RecipeSummaryEntity>
|
|
||||||
|
|
||||||
suspend fun refreshAll(recipes: List<RecipeSummaryEntity>)
|
|
||||||
|
|
||||||
suspend fun clearAllLocalData()
|
|
||||||
|
|
||||||
suspend fun saveRecipeInfo(recipe: FullRecipeInfo)
|
|
||||||
|
|
||||||
suspend fun queryRecipeInfo(recipeId: String): FullRecipeEntity?
|
|
||||||
|
|
||||||
suspend fun updateFavoriteRecipes(favorites: List<String>)
|
|
||||||
|
|
||||||
suspend fun deleteRecipe(entity: RecipeSummaryEntity)
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package gq.kirmanak.mealient.data.recipes.impl
|
package gq.kirmanak.mealient.data.recipes.impl
|
||||||
|
|
||||||
import androidx.paging.InvalidatingPagingSourceFactory
|
import androidx.paging.InvalidatingPagingSourceFactory
|
||||||
import gq.kirmanak.mealient.data.recipes.db.RecipeStorage
|
import gq.kirmanak.mealient.database.recipe.RecipeStorage
|
||||||
import gq.kirmanak.mealient.logging.Logger
|
import gq.kirmanak.mealient.logging.Logger
|
||||||
import java.util.concurrent.atomic.AtomicReference
|
import java.util.concurrent.atomic.AtomicReference
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|||||||
@@ -4,12 +4,13 @@ import androidx.paging.ExperimentalPagingApi
|
|||||||
import androidx.paging.Pager
|
import androidx.paging.Pager
|
||||||
import androidx.paging.PagingConfig
|
import androidx.paging.PagingConfig
|
||||||
import gq.kirmanak.mealient.data.recipes.RecipeRepo
|
import gq.kirmanak.mealient.data.recipes.RecipeRepo
|
||||||
import gq.kirmanak.mealient.data.recipes.db.RecipeStorage
|
|
||||||
import gq.kirmanak.mealient.data.recipes.network.RecipeDataSource
|
import gq.kirmanak.mealient.data.recipes.network.RecipeDataSource
|
||||||
import gq.kirmanak.mealient.database.recipe.entity.FullRecipeEntity
|
import gq.kirmanak.mealient.database.recipe.RecipeStorage
|
||||||
import gq.kirmanak.mealient.database.recipe.entity.RecipeSummaryEntity
|
import gq.kirmanak.mealient.database.recipe.entity.RecipeSummaryEntity
|
||||||
|
import gq.kirmanak.mealient.database.recipe.entity.RecipeWithSummaryAndIngredientsAndInstructions
|
||||||
import gq.kirmanak.mealient.datasource.runCatchingExceptCancel
|
import gq.kirmanak.mealient.datasource.runCatchingExceptCancel
|
||||||
import gq.kirmanak.mealient.logging.Logger
|
import gq.kirmanak.mealient.logging.Logger
|
||||||
|
import gq.kirmanak.mealient.model_mapper.ModelMapper
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@@ -21,6 +22,7 @@ class RecipeRepoImpl @Inject constructor(
|
|||||||
private val pagingSourceFactory: RecipePagingSourceFactory,
|
private val pagingSourceFactory: RecipePagingSourceFactory,
|
||||||
private val dataSource: RecipeDataSource,
|
private val dataSource: RecipeDataSource,
|
||||||
private val logger: Logger,
|
private val logger: Logger,
|
||||||
|
private val modelMapper: ModelMapper,
|
||||||
) : RecipeRepo {
|
) : RecipeRepo {
|
||||||
|
|
||||||
override fun createPager(): Pager<Int, RecipeSummaryEntity> {
|
override fun createPager(): Pager<Int, RecipeSummaryEntity> {
|
||||||
@@ -45,13 +47,21 @@ class RecipeRepoImpl @Inject constructor(
|
|||||||
override suspend fun refreshRecipeInfo(recipeSlug: String): Result<Unit> {
|
override suspend fun refreshRecipeInfo(recipeSlug: String): Result<Unit> {
|
||||||
logger.v { "refreshRecipeInfo() called with: recipeSlug = $recipeSlug" }
|
logger.v { "refreshRecipeInfo() called with: recipeSlug = $recipeSlug" }
|
||||||
return runCatchingExceptCancel {
|
return runCatchingExceptCancel {
|
||||||
storage.saveRecipeInfo(dataSource.requestRecipeInfo(recipeSlug))
|
val info = dataSource.requestRecipeInfo(recipeSlug)
|
||||||
|
val entity = modelMapper.toRecipeEntity(info)
|
||||||
|
val ingredients = info.recipeIngredients.map {
|
||||||
|
modelMapper.toRecipeIngredientEntity(it, entity.remoteId)
|
||||||
|
}
|
||||||
|
val instructions = info.recipeInstructions.map {
|
||||||
|
modelMapper.toRecipeInstructionEntity(it, entity.remoteId)
|
||||||
|
}
|
||||||
|
storage.saveRecipeInfo(entity, ingredients, instructions)
|
||||||
}.onFailure {
|
}.onFailure {
|
||||||
logger.e(it) { "loadRecipeInfo: can't update full recipe info" }
|
logger.e(it) { "loadRecipeInfo: can't update full recipe info" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun loadRecipeInfo(recipeId: String): FullRecipeEntity? {
|
override suspend fun loadRecipeInfo(recipeId: String): RecipeWithSummaryAndIngredientsAndInstructions? {
|
||||||
logger.v { "loadRecipeInfo() called with: recipeId = $recipeId" }
|
logger.v { "loadRecipeInfo() called with: recipeId = $recipeId" }
|
||||||
val recipeInfo = storage.queryRecipeInfo(recipeId)
|
val recipeInfo = storage.queryRecipeInfo(recipeId)
|
||||||
logger.v { "loadRecipeInfo() returned: $recipeInfo" }
|
logger.v { "loadRecipeInfo() returned: $recipeInfo" }
|
||||||
|
|||||||
@@ -5,12 +5,12 @@ import androidx.paging.*
|
|||||||
import androidx.paging.LoadType.PREPEND
|
import androidx.paging.LoadType.PREPEND
|
||||||
import androidx.paging.LoadType.REFRESH
|
import androidx.paging.LoadType.REFRESH
|
||||||
import gq.kirmanak.mealient.architecture.configuration.AppDispatchers
|
import gq.kirmanak.mealient.architecture.configuration.AppDispatchers
|
||||||
import gq.kirmanak.mealient.data.recipes.db.RecipeStorage
|
|
||||||
import gq.kirmanak.mealient.data.recipes.network.RecipeDataSource
|
import gq.kirmanak.mealient.data.recipes.network.RecipeDataSource
|
||||||
|
import gq.kirmanak.mealient.database.recipe.RecipeStorage
|
||||||
import gq.kirmanak.mealient.database.recipe.entity.RecipeSummaryEntity
|
import gq.kirmanak.mealient.database.recipe.entity.RecipeSummaryEntity
|
||||||
import gq.kirmanak.mealient.datasource.runCatchingExceptCancel
|
import gq.kirmanak.mealient.datasource.runCatchingExceptCancel
|
||||||
import gq.kirmanak.mealient.extensions.toRecipeSummaryEntity
|
|
||||||
import gq.kirmanak.mealient.logging.Logger
|
import gq.kirmanak.mealient.logging.Logger
|
||||||
|
import gq.kirmanak.mealient.model_mapper.ModelMapper
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.coroutineScope
|
import kotlinx.coroutines.coroutineScope
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
@@ -24,6 +24,7 @@ class RecipesRemoteMediator @Inject constructor(
|
|||||||
private val network: RecipeDataSource,
|
private val network: RecipeDataSource,
|
||||||
private val pagingSourceFactory: RecipePagingSourceFactory,
|
private val pagingSourceFactory: RecipePagingSourceFactory,
|
||||||
private val logger: Logger,
|
private val logger: Logger,
|
||||||
|
private val modelMapper: ModelMapper,
|
||||||
private val dispatchers: AppDispatchers,
|
private val dispatchers: AppDispatchers,
|
||||||
) : RemoteMediator<Int, RecipeSummaryEntity>() {
|
) : RemoteMediator<Int, RecipeSummaryEntity>() {
|
||||||
|
|
||||||
@@ -75,7 +76,7 @@ class RecipesRemoteMediator @Inject constructor(
|
|||||||
val entities = withContext(dispatchers.default) {
|
val entities = withContext(dispatchers.default) {
|
||||||
recipes.map { recipe ->
|
recipes.map { recipe ->
|
||||||
val isFavorite = favorites.contains(recipe.slug)
|
val isFavorite = favorites.contains(recipe.slug)
|
||||||
recipe.toRecipeSummaryEntity(isFavorite)
|
modelMapper.toRecipeSummaryEntity(recipe, isFavorite)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (loadType == REFRESH) storage.refreshAll(entities)
|
if (loadType == REFRESH) storage.refreshAll(entities)
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
package gq.kirmanak.mealient.data.recipes.network
|
package gq.kirmanak.mealient.data.recipes.network
|
||||||
|
|
||||||
|
import gq.kirmanak.mealient.datasource.models.FullRecipeInfo
|
||||||
|
import gq.kirmanak.mealient.datasource.models.RecipeSummaryInfo
|
||||||
|
|
||||||
interface RecipeDataSource {
|
interface RecipeDataSource {
|
||||||
suspend fun requestRecipes(start: Int, limit: Int): List<RecipeSummaryInfo>
|
suspend fun requestRecipes(start: Int, limit: Int): List<RecipeSummaryInfo>
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package gq.kirmanak.mealient.data.share
|
package gq.kirmanak.mealient.data.share
|
||||||
|
|
||||||
|
import gq.kirmanak.mealient.datasource.models.ParseRecipeURLInfo
|
||||||
|
|
||||||
interface ParseRecipeDataSource {
|
interface ParseRecipeDataSource {
|
||||||
|
|
||||||
suspend fun parseRecipeFromURL(parseRecipeURLInfo: ParseRecipeURLInfo): String
|
suspend fun parseRecipeFromURL(parseRecipeURLInfo: ParseRecipeURLInfo): String
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package gq.kirmanak.mealient.data.share
|
package gq.kirmanak.mealient.data.share
|
||||||
|
|
||||||
import androidx.core.util.PatternsCompat
|
import androidx.core.util.PatternsCompat
|
||||||
|
import gq.kirmanak.mealient.datasource.models.ParseRecipeURLInfo
|
||||||
import gq.kirmanak.mealient.logging.Logger
|
import gq.kirmanak.mealient.logging.Logger
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import gq.kirmanak.mealient.data.auth.impl.AuthDataSourceImpl
|
|||||||
import gq.kirmanak.mealient.data.auth.impl.AuthRepoImpl
|
import gq.kirmanak.mealient.data.auth.impl.AuthRepoImpl
|
||||||
import gq.kirmanak.mealient.data.auth.impl.AuthStorageImpl
|
import gq.kirmanak.mealient.data.auth.impl.AuthStorageImpl
|
||||||
import gq.kirmanak.mealient.datasource.AuthenticationProvider
|
import gq.kirmanak.mealient.datasource.AuthenticationProvider
|
||||||
|
import gq.kirmanak.mealient.shopping_lists.repo.ShoppingListsAuthRepo
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
@@ -45,4 +46,8 @@ interface AuthModule {
|
|||||||
@Binds
|
@Binds
|
||||||
@Singleton
|
@Singleton
|
||||||
fun bindAuthStorage(authStorageImpl: AuthStorageImpl): AuthStorage
|
fun bindAuthStorage(authStorageImpl: AuthStorageImpl): AuthStorage
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@Singleton
|
||||||
|
fun bindShoppingListsAuthRepo(impl: AuthRepoImpl): ShoppingListsAuthRepo
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,8 +10,6 @@ import dagger.hilt.components.SingletonComponent
|
|||||||
import gq.kirmanak.mealient.R
|
import gq.kirmanak.mealient.R
|
||||||
import gq.kirmanak.mealient.data.network.MealieDataSourceWrapper
|
import gq.kirmanak.mealient.data.network.MealieDataSourceWrapper
|
||||||
import gq.kirmanak.mealient.data.recipes.RecipeRepo
|
import gq.kirmanak.mealient.data.recipes.RecipeRepo
|
||||||
import gq.kirmanak.mealient.data.recipes.db.RecipeStorage
|
|
||||||
import gq.kirmanak.mealient.data.recipes.db.RecipeStorageImpl
|
|
||||||
import gq.kirmanak.mealient.data.recipes.impl.*
|
import gq.kirmanak.mealient.data.recipes.impl.*
|
||||||
import gq.kirmanak.mealient.data.recipes.network.RecipeDataSource
|
import gq.kirmanak.mealient.data.recipes.network.RecipeDataSource
|
||||||
import gq.kirmanak.mealient.database.recipe.entity.RecipeSummaryEntity
|
import gq.kirmanak.mealient.database.recipe.entity.RecipeSummaryEntity
|
||||||
@@ -27,10 +25,6 @@ interface RecipeModule {
|
|||||||
@Singleton
|
@Singleton
|
||||||
fun provideRecipeDataSource(mealieDataSourceWrapper: MealieDataSourceWrapper): RecipeDataSource
|
fun provideRecipeDataSource(mealieDataSourceWrapper: MealieDataSourceWrapper): RecipeDataSource
|
||||||
|
|
||||||
@Binds
|
|
||||||
@Singleton
|
|
||||||
fun provideRecipeStorage(recipeStorageImpl: RecipeStorageImpl): RecipeStorage
|
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
@Singleton
|
@Singleton
|
||||||
fun provideRecipeRepo(recipeRepoImpl: RecipeRepoImpl): RecipeRepo
|
fun provideRecipeRepo(recipeRepoImpl: RecipeRepoImpl): RecipeRepo
|
||||||
|
|||||||
@@ -1,224 +0,0 @@
|
|||||||
package gq.kirmanak.mealient.extensions
|
|
||||||
|
|
||||||
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.data.baseurl.VersionInfo
|
|
||||||
import gq.kirmanak.mealient.data.recipes.network.FullRecipeInfo
|
|
||||||
import gq.kirmanak.mealient.data.recipes.network.RecipeIngredientInfo
|
|
||||||
import gq.kirmanak.mealient.data.recipes.network.RecipeInstructionInfo
|
|
||||||
import gq.kirmanak.mealient.data.recipes.network.RecipeSettingsInfo
|
|
||||||
import gq.kirmanak.mealient.data.recipes.network.RecipeSummaryInfo
|
|
||||||
import gq.kirmanak.mealient.data.share.ParseRecipeURLInfo
|
|
||||||
import gq.kirmanak.mealient.database.recipe.entity.RecipeEntity
|
|
||||||
import gq.kirmanak.mealient.database.recipe.entity.RecipeIngredientEntity
|
|
||||||
import gq.kirmanak.mealient.database.recipe.entity.RecipeInstructionEntity
|
|
||||||
import gq.kirmanak.mealient.database.recipe.entity.RecipeSummaryEntity
|
|
||||||
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.datasource.v0.models.GetRecipeIngredientResponseV0
|
|
||||||
import gq.kirmanak.mealient.datasource.v0.models.GetRecipeInstructionResponseV0
|
|
||||||
import gq.kirmanak.mealient.datasource.v0.models.GetRecipeResponseV0
|
|
||||||
import gq.kirmanak.mealient.datasource.v0.models.GetRecipeSummaryResponseV0
|
|
||||||
import gq.kirmanak.mealient.datasource.v0.models.ParseRecipeURLRequestV0
|
|
||||||
import gq.kirmanak.mealient.datasource.v0.models.VersionResponseV0
|
|
||||||
import gq.kirmanak.mealient.datasource.v1.models.AddRecipeIngredientV1
|
|
||||||
import gq.kirmanak.mealient.datasource.v1.models.AddRecipeInstructionV1
|
|
||||||
import gq.kirmanak.mealient.datasource.v1.models.AddRecipeSettingsV1
|
|
||||||
import gq.kirmanak.mealient.datasource.v1.models.CreateRecipeRequestV1
|
|
||||||
import gq.kirmanak.mealient.datasource.v1.models.GetRecipeIngredientResponseV1
|
|
||||||
import gq.kirmanak.mealient.datasource.v1.models.GetRecipeInstructionResponseV1
|
|
||||||
import gq.kirmanak.mealient.datasource.v1.models.GetRecipeResponseV1
|
|
||||||
import gq.kirmanak.mealient.datasource.v1.models.GetRecipeSettingsResponseV1
|
|
||||||
import gq.kirmanak.mealient.datasource.v1.models.GetRecipeSummaryResponseV1
|
|
||||||
import gq.kirmanak.mealient.datasource.v1.models.ParseRecipeURLRequestV1
|
|
||||||
import gq.kirmanak.mealient.datasource.v1.models.UpdateRecipeRequestV1
|
|
||||||
import gq.kirmanak.mealient.datasource.v1.models.VersionResponseV1
|
|
||||||
import gq.kirmanak.mealient.datastore.recipe.AddRecipeDraft
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
fun FullRecipeInfo.toRecipeEntity() = RecipeEntity(
|
|
||||||
remoteId = remoteId,
|
|
||||||
recipeYield = recipeYield,
|
|
||||||
disableAmounts = settings.disableAmounts,
|
|
||||||
)
|
|
||||||
|
|
||||||
fun RecipeIngredientInfo.toRecipeIngredientEntity(remoteId: String) = RecipeIngredientEntity(
|
|
||||||
recipeId = remoteId,
|
|
||||||
note = note,
|
|
||||||
unit = unit,
|
|
||||||
food = food,
|
|
||||||
quantity = quantity,
|
|
||||||
title = title,
|
|
||||||
)
|
|
||||||
|
|
||||||
fun RecipeInstructionInfo.toRecipeInstructionEntity(remoteId: String) = RecipeInstructionEntity(
|
|
||||||
recipeId = remoteId,
|
|
||||||
text = text
|
|
||||||
)
|
|
||||||
|
|
||||||
fun GetRecipeSummaryResponseV0.toRecipeSummaryInfo() = RecipeSummaryInfo(
|
|
||||||
remoteId = remoteId.toString(),
|
|
||||||
name = name,
|
|
||||||
slug = slug,
|
|
||||||
description = description,
|
|
||||||
dateAdded = dateAdded,
|
|
||||||
dateUpdated = dateUpdated,
|
|
||||||
imageId = slug,
|
|
||||||
)
|
|
||||||
|
|
||||||
fun GetRecipeSummaryResponseV1.toRecipeSummaryInfo() = RecipeSummaryInfo(
|
|
||||||
remoteId = remoteId,
|
|
||||||
name = name,
|
|
||||||
slug = slug,
|
|
||||||
description = description,
|
|
||||||
dateAdded = dateAdded,
|
|
||||||
dateUpdated = dateUpdated,
|
|
||||||
imageId = remoteId,
|
|
||||||
)
|
|
||||||
|
|
||||||
fun RecipeSummaryInfo.toRecipeSummaryEntity(isFavorite: Boolean) = RecipeSummaryEntity(
|
|
||||||
remoteId = remoteId,
|
|
||||||
name = name,
|
|
||||||
slug = slug,
|
|
||||||
description = description,
|
|
||||||
dateAdded = dateAdded,
|
|
||||||
dateUpdated = dateUpdated,
|
|
||||||
imageId = imageId,
|
|
||||||
isFavorite = isFavorite,
|
|
||||||
)
|
|
||||||
|
|
||||||
fun VersionResponseV0.toVersionInfo() = VersionInfo(version)
|
|
||||||
|
|
||||||
fun VersionResponseV1.toVersionInfo() = VersionInfo(version)
|
|
||||||
|
|
||||||
fun AddRecipeDraft.toAddRecipeInfo() = AddRecipeInfo(
|
|
||||||
name = recipeName,
|
|
||||||
description = recipeDescription,
|
|
||||||
recipeYield = recipeYield,
|
|
||||||
recipeIngredient = recipeIngredients.map { AddRecipeIngredientInfo(note = it) },
|
|
||||||
recipeInstructions = recipeInstructions.map { AddRecipeInstructionInfo(text = it) },
|
|
||||||
settings = AddRecipeSettingsInfo(
|
|
||||||
public = isRecipePublic,
|
|
||||||
disableComments = areCommentsDisabled,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
fun AddRecipeInfo.toDraft(): AddRecipeDraft = AddRecipeDraft(
|
|
||||||
recipeName = name,
|
|
||||||
recipeDescription = description,
|
|
||||||
recipeYield = recipeYield,
|
|
||||||
recipeInstructions = recipeInstructions.map { it.text },
|
|
||||||
recipeIngredients = recipeIngredient.map { it.note },
|
|
||||||
isRecipePublic = settings.public,
|
|
||||||
areCommentsDisabled = settings.disableComments,
|
|
||||||
)
|
|
||||||
|
|
||||||
fun GetRecipeResponseV0.toFullRecipeInfo() = FullRecipeInfo(
|
|
||||||
remoteId = remoteId.toString(),
|
|
||||||
name = name,
|
|
||||||
recipeYield = recipeYield,
|
|
||||||
recipeIngredients = recipeIngredients.map { it.toRecipeIngredientInfo() },
|
|
||||||
recipeInstructions = recipeInstructions.map { it.toRecipeInstructionInfo() },
|
|
||||||
settings = RecipeSettingsInfo(disableAmounts = true)
|
|
||||||
)
|
|
||||||
|
|
||||||
fun GetRecipeIngredientResponseV0.toRecipeIngredientInfo() = RecipeIngredientInfo(
|
|
||||||
note = note,
|
|
||||||
unit = null,
|
|
||||||
food = null,
|
|
||||||
quantity = 1.0,
|
|
||||||
title = null,
|
|
||||||
)
|
|
||||||
|
|
||||||
fun GetRecipeInstructionResponseV0.toRecipeInstructionInfo() = RecipeInstructionInfo(
|
|
||||||
text = text
|
|
||||||
)
|
|
||||||
|
|
||||||
fun GetRecipeResponseV1.toFullRecipeInfo() = FullRecipeInfo(
|
|
||||||
remoteId = remoteId,
|
|
||||||
name = name,
|
|
||||||
recipeYield = recipeYield,
|
|
||||||
recipeIngredients = recipeIngredients.map { it.toRecipeIngredientInfo() },
|
|
||||||
recipeInstructions = recipeInstructions.map { it.toRecipeInstructionInfo() },
|
|
||||||
settings = settings.toRecipeSettingsInfo(),
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun GetRecipeSettingsResponseV1.toRecipeSettingsInfo() = RecipeSettingsInfo(
|
|
||||||
disableAmounts = disableAmount,
|
|
||||||
)
|
|
||||||
|
|
||||||
fun GetRecipeIngredientResponseV1.toRecipeIngredientInfo() = RecipeIngredientInfo(
|
|
||||||
note = note,
|
|
||||||
unit = unit?.name,
|
|
||||||
food = food?.name,
|
|
||||||
quantity = quantity,
|
|
||||||
title = title,
|
|
||||||
)
|
|
||||||
|
|
||||||
fun GetRecipeInstructionResponseV1.toRecipeInstructionInfo() = RecipeInstructionInfo(
|
|
||||||
text = text
|
|
||||||
)
|
|
||||||
|
|
||||||
fun AddRecipeInfo.toV0Request() = AddRecipeRequestV0(
|
|
||||||
name = name,
|
|
||||||
description = description,
|
|
||||||
recipeYield = recipeYield,
|
|
||||||
recipeIngredient = recipeIngredient.map { it.toV0Ingredient() },
|
|
||||||
recipeInstructions = recipeInstructions.map { it.toV0Instruction() },
|
|
||||||
settings = settings.toV0Settings(),
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun AddRecipeSettingsInfo.toV0Settings() = AddRecipeSettingsV0(
|
|
||||||
disableComments = disableComments,
|
|
||||||
public = public,
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun AddRecipeIngredientInfo.toV0Ingredient() = AddRecipeIngredientV0(
|
|
||||||
note = note,
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun AddRecipeInstructionInfo.toV0Instruction() = AddRecipeInstructionV0(
|
|
||||||
text = text,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
fun AddRecipeInfo.toV1CreateRequest() = CreateRecipeRequestV1(
|
|
||||||
name = name,
|
|
||||||
)
|
|
||||||
|
|
||||||
fun AddRecipeInfo.toV1UpdateRequest() = UpdateRecipeRequestV1(
|
|
||||||
description = description,
|
|
||||||
recipeYield = recipeYield,
|
|
||||||
recipeIngredient = recipeIngredient.map { it.toV1Ingredient() },
|
|
||||||
recipeInstructions = recipeInstructions.map { it.toV1Instruction() },
|
|
||||||
settings = settings.toV1Settings(),
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun AddRecipeSettingsInfo.toV1Settings() = AddRecipeSettingsV1(
|
|
||||||
disableComments = disableComments,
|
|
||||||
public = public,
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun AddRecipeIngredientInfo.toV1Ingredient() = AddRecipeIngredientV1(
|
|
||||||
id = UUID.randomUUID().toString(),
|
|
||||||
note = note,
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun AddRecipeInstructionInfo.toV1Instruction() = AddRecipeInstructionV1(
|
|
||||||
id = UUID.randomUUID().toString(),
|
|
||||||
text = text,
|
|
||||||
ingredientReferences = emptyList(),
|
|
||||||
)
|
|
||||||
|
|
||||||
fun ParseRecipeURLInfo.toV1Request() = ParseRecipeURLRequestV1(
|
|
||||||
url = url,
|
|
||||||
includeTags = includeTags,
|
|
||||||
)
|
|
||||||
|
|
||||||
fun ParseRecipeURLInfo.toV0Request() = ParseRecipeURLRequestV0(
|
|
||||||
url = url,
|
|
||||||
)
|
|
||||||
@@ -15,11 +15,14 @@ import gq.kirmanak.mealient.NavGraphDirections.Companion.actionGlobalAddRecipeFr
|
|||||||
import gq.kirmanak.mealient.NavGraphDirections.Companion.actionGlobalAuthenticationFragment
|
import gq.kirmanak.mealient.NavGraphDirections.Companion.actionGlobalAuthenticationFragment
|
||||||
import gq.kirmanak.mealient.NavGraphDirections.Companion.actionGlobalBaseURLFragment
|
import gq.kirmanak.mealient.NavGraphDirections.Companion.actionGlobalBaseURLFragment
|
||||||
import gq.kirmanak.mealient.NavGraphDirections.Companion.actionGlobalRecipesListFragment
|
import gq.kirmanak.mealient.NavGraphDirections.Companion.actionGlobalRecipesListFragment
|
||||||
|
import gq.kirmanak.mealient.NavGraphDirections.Companion.actionGlobalShoppingListsFragment
|
||||||
import gq.kirmanak.mealient.R
|
import gq.kirmanak.mealient.R
|
||||||
import gq.kirmanak.mealient.databinding.MainActivityBinding
|
import gq.kirmanak.mealient.databinding.MainActivityBinding
|
||||||
import gq.kirmanak.mealient.extensions.collectWhenResumed
|
import gq.kirmanak.mealient.extensions.collectWhenResumed
|
||||||
import gq.kirmanak.mealient.extensions.observeOnce
|
import gq.kirmanak.mealient.extensions.observeOnce
|
||||||
|
import gq.kirmanak.mealient.ui.ActivityUiState
|
||||||
import gq.kirmanak.mealient.ui.BaseActivity
|
import gq.kirmanak.mealient.ui.BaseActivity
|
||||||
|
import gq.kirmanak.mealient.ui.CheckableMenuItem
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class MainActivity : BaseActivity<MainActivityBinding>(
|
class MainActivity : BaseActivity<MainActivityBinding>(
|
||||||
@@ -60,7 +63,7 @@ class MainActivity : BaseActivity<MainActivityBinding>(
|
|||||||
viewModel.onSearchQuery(query.trim().takeUnless { it.isEmpty() })
|
viewModel.onSearchQuery(query.trim().takeUnless { it.isEmpty() })
|
||||||
}
|
}
|
||||||
binding.navigationView.setNavigationItemSelectedListener(::onNavigationItemSelected)
|
binding.navigationView.setNavigationItemSelectedListener(::onNavigationItemSelected)
|
||||||
viewModel.uiStateLive.observe(this, ::onUiStateChange)
|
collectWhenResumed(viewModel.uiState, ::onUiStateChange)
|
||||||
collectWhenResumed(viewModel.clearSearchViewFocus) {
|
collectWhenResumed(viewModel.clearSearchViewFocus) {
|
||||||
logger.d { "clearSearchViewFocus(): received event" }
|
logger.d { "clearSearchViewFocus(): received event" }
|
||||||
binding.toolbar.clearSearchFocus()
|
binding.toolbar.clearSearchFocus()
|
||||||
@@ -77,6 +80,7 @@ class MainActivity : BaseActivity<MainActivityBinding>(
|
|||||||
val directions = when (menuItem.itemId) {
|
val directions = when (menuItem.itemId) {
|
||||||
R.id.add_recipe -> actionGlobalAddRecipeFragment()
|
R.id.add_recipe -> actionGlobalAddRecipeFragment()
|
||||||
R.id.recipes_list -> actionGlobalRecipesListFragment()
|
R.id.recipes_list -> actionGlobalRecipesListFragment()
|
||||||
|
R.id.shopping_lists -> actionGlobalShoppingListsFragment()
|
||||||
R.id.change_url -> actionGlobalBaseURLFragment(false)
|
R.id.change_url -> actionGlobalBaseURLFragment(false)
|
||||||
R.id.login -> actionGlobalAuthenticationFragment()
|
R.id.login -> actionGlobalAuthenticationFragment()
|
||||||
R.id.logout -> {
|
R.id.logout -> {
|
||||||
@@ -90,15 +94,24 @@ class MainActivity : BaseActivity<MainActivityBinding>(
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onUiStateChange(uiState: MainActivityUiState) {
|
private fun onUiStateChange(uiState: ActivityUiState) {
|
||||||
logger.v { "onUiStateChange() called with: uiState = $uiState" }
|
logger.v { "onUiStateChange() called with: uiState = $uiState" }
|
||||||
|
val checkedMenuItem = when (uiState.checkedMenuItem) {
|
||||||
|
CheckableMenuItem.ShoppingLists -> R.id.shopping_lists
|
||||||
|
CheckableMenuItem.RecipesList -> R.id.recipes_list
|
||||||
|
CheckableMenuItem.AddRecipe -> R.id.add_recipe
|
||||||
|
CheckableMenuItem.ChangeUrl -> R.id.change_url
|
||||||
|
CheckableMenuItem.Login -> R.id.login
|
||||||
|
null -> null
|
||||||
|
}
|
||||||
for (menuItem in binding.navigationView.menu.iterator()) {
|
for (menuItem in binding.navigationView.menu.iterator()) {
|
||||||
val itemId = menuItem.itemId
|
val itemId = menuItem.itemId
|
||||||
when (itemId) {
|
when (itemId) {
|
||||||
R.id.logout -> menuItem.isVisible = uiState.canShowLogout
|
R.id.logout -> menuItem.isVisible = uiState.canShowLogout
|
||||||
R.id.login -> menuItem.isVisible = uiState.canShowLogin
|
R.id.login -> menuItem.isVisible = uiState.canShowLogin
|
||||||
|
R.id.shopping_lists -> menuItem.isVisible = uiState.v1MenuItemsVisible
|
||||||
}
|
}
|
||||||
menuItem.isChecked = itemId == uiState.checkedMenuItemId
|
menuItem.isChecked = itemId == checkedMenuItem
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.toolbar.isVisible = uiState.navigationVisible
|
binding.toolbar.isVisible = uiState.navigationVisible
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
package gq.kirmanak.mealient.ui.activity
|
|
||||||
|
|
||||||
import androidx.annotation.IdRes
|
|
||||||
|
|
||||||
data class MainActivityUiState(
|
|
||||||
val isAuthorized: Boolean = false,
|
|
||||||
val navigationVisible: Boolean = false,
|
|
||||||
val searchVisible: Boolean = false,
|
|
||||||
@IdRes val checkedMenuItemId: Int? = null,
|
|
||||||
) {
|
|
||||||
val canShowLogin: Boolean get() = !isAuthorized
|
|
||||||
|
|
||||||
val canShowLogout: Boolean get() = isAuthorized
|
|
||||||
}
|
|
||||||
@@ -1,16 +1,23 @@
|
|||||||
package gq.kirmanak.mealient.ui.activity
|
package gq.kirmanak.mealient.ui.activity
|
||||||
|
|
||||||
import androidx.lifecycle.*
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import gq.kirmanak.mealient.R
|
import gq.kirmanak.mealient.R
|
||||||
import gq.kirmanak.mealient.data.auth.AuthRepo
|
import gq.kirmanak.mealient.data.auth.AuthRepo
|
||||||
import gq.kirmanak.mealient.data.baseurl.ServerInfoRepo
|
import gq.kirmanak.mealient.data.baseurl.ServerInfoRepo
|
||||||
|
import gq.kirmanak.mealient.data.baseurl.ServerVersion
|
||||||
import gq.kirmanak.mealient.data.disclaimer.DisclaimerStorage
|
import gq.kirmanak.mealient.data.disclaimer.DisclaimerStorage
|
||||||
import gq.kirmanak.mealient.data.recipes.RecipeRepo
|
import gq.kirmanak.mealient.data.recipes.RecipeRepo
|
||||||
import gq.kirmanak.mealient.logging.Logger
|
import gq.kirmanak.mealient.logging.Logger
|
||||||
|
import gq.kirmanak.mealient.ui.ActivityUiState
|
||||||
|
import gq.kirmanak.mealient.ui.ActivityUiStateController
|
||||||
import gq.kirmanak.mealient.ui.baseurl.BaseURLFragmentArgs
|
import gq.kirmanak.mealient.ui.baseurl.BaseURLFragmentArgs
|
||||||
import kotlinx.coroutines.channels.Channel
|
import kotlinx.coroutines.channels.Channel
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.flow.receiveAsFlow
|
import kotlinx.coroutines.flow.receiveAsFlow
|
||||||
@@ -24,14 +31,10 @@ class MainActivityViewModel @Inject constructor(
|
|||||||
private val disclaimerStorage: DisclaimerStorage,
|
private val disclaimerStorage: DisclaimerStorage,
|
||||||
private val serverInfoRepo: ServerInfoRepo,
|
private val serverInfoRepo: ServerInfoRepo,
|
||||||
private val recipeRepo: RecipeRepo,
|
private val recipeRepo: RecipeRepo,
|
||||||
|
private val activityUiStateController: ActivityUiStateController,
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
private val _uiState = MutableLiveData(MainActivityUiState())
|
val uiState: StateFlow<ActivityUiState> = activityUiStateController.getUiStateFlow()
|
||||||
val uiStateLive: LiveData<MainActivityUiState>
|
|
||||||
get() = _uiState.distinctUntilChanged()
|
|
||||||
var uiState: MainActivityUiState
|
|
||||||
get() = checkNotNull(_uiState.value) { "UiState must not be null" }
|
|
||||||
private set(value) = _uiState.postValue(value)
|
|
||||||
|
|
||||||
private val _startDestination = MutableLiveData<StartDestinationInfo>()
|
private val _startDestination = MutableLiveData<StartDestinationInfo>()
|
||||||
val startDestination: LiveData<StartDestinationInfo> = _startDestination
|
val startDestination: LiveData<StartDestinationInfo> = _startDestination
|
||||||
@@ -44,6 +47,10 @@ class MainActivityViewModel @Inject constructor(
|
|||||||
.onEach { isAuthorized -> updateUiState { it.copy(isAuthorized = isAuthorized) } }
|
.onEach { isAuthorized -> updateUiState { it.copy(isAuthorized = isAuthorized) } }
|
||||||
.launchIn(viewModelScope)
|
.launchIn(viewModelScope)
|
||||||
|
|
||||||
|
serverInfoRepo.versionUpdates()
|
||||||
|
.onEach { version -> updateUiState { it.copy(v1MenuItemsVisible = version == ServerVersion.V1) } }
|
||||||
|
.launchIn(viewModelScope)
|
||||||
|
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
_startDestination.value = when {
|
_startDestination.value = when {
|
||||||
!disclaimerStorage.isDisclaimerAccepted() -> {
|
!disclaimerStorage.isDisclaimerAccepted() -> {
|
||||||
@@ -59,8 +66,8 @@ class MainActivityViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateUiState(updater: (MainActivityUiState) -> MainActivityUiState) {
|
fun updateUiState(updater: (ActivityUiState) -> ActivityUiState) {
|
||||||
uiState = updater(uiState)
|
activityUiStateController.updateUiState(updater)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun logout() {
|
fun logout() {
|
||||||
|
|||||||
@@ -12,15 +12,16 @@ import androidx.fragment.app.viewModels
|
|||||||
import by.kirich1409.viewbindingdelegate.viewBinding
|
import by.kirich1409.viewbindingdelegate.viewBinding
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import gq.kirmanak.mealient.R
|
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.FragmentAddRecipeBinding
|
||||||
import gq.kirmanak.mealient.databinding.ViewSingleInputBinding
|
import gq.kirmanak.mealient.databinding.ViewSingleInputBinding
|
||||||
|
import gq.kirmanak.mealient.datasource.models.AddRecipeInfo
|
||||||
|
import gq.kirmanak.mealient.datasource.models.AddRecipeIngredientInfo
|
||||||
|
import gq.kirmanak.mealient.datasource.models.AddRecipeInstructionInfo
|
||||||
|
import gq.kirmanak.mealient.datasource.models.AddRecipeSettingsInfo
|
||||||
import gq.kirmanak.mealient.extensions.checkIfInputIsEmpty
|
import gq.kirmanak.mealient.extensions.checkIfInputIsEmpty
|
||||||
import gq.kirmanak.mealient.extensions.collectWhenViewResumed
|
import gq.kirmanak.mealient.extensions.collectWhenViewResumed
|
||||||
import gq.kirmanak.mealient.logging.Logger
|
import gq.kirmanak.mealient.logging.Logger
|
||||||
|
import gq.kirmanak.mealient.ui.CheckableMenuItem
|
||||||
import gq.kirmanak.mealient.ui.activity.MainActivityViewModel
|
import gq.kirmanak.mealient.ui.activity.MainActivityViewModel
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@@ -41,7 +42,7 @@ class AddRecipeFragment : Fragment(R.layout.fragment_add_recipe) {
|
|||||||
it.copy(
|
it.copy(
|
||||||
navigationVisible = true,
|
navigationVisible = true,
|
||||||
searchVisible = false,
|
searchVisible = false,
|
||||||
checkedMenuItemId = R.id.add_recipe,
|
checkedMenuItem = CheckableMenuItem.AddRecipe,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
viewModel.loadPreservedRequest()
|
viewModel.loadPreservedRequest()
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package gq.kirmanak.mealient.ui.add
|
|||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import gq.kirmanak.mealient.data.add.AddRecipeInfo
|
|
||||||
import gq.kirmanak.mealient.data.add.AddRecipeRepo
|
import gq.kirmanak.mealient.data.add.AddRecipeRepo
|
||||||
|
import gq.kirmanak.mealient.datasource.models.AddRecipeInfo
|
||||||
import gq.kirmanak.mealient.datasource.runCatchingExceptCancel
|
import gq.kirmanak.mealient.datasource.runCatchingExceptCancel
|
||||||
import gq.kirmanak.mealient.logging.Logger
|
import gq.kirmanak.mealient.logging.Logger
|
||||||
import kotlinx.coroutines.channels.Channel
|
import kotlinx.coroutines.channels.Channel
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import gq.kirmanak.mealient.databinding.FragmentAuthenticationBinding
|
|||||||
import gq.kirmanak.mealient.datasource.NetworkError
|
import gq.kirmanak.mealient.datasource.NetworkError
|
||||||
import gq.kirmanak.mealient.extensions.checkIfInputIsEmpty
|
import gq.kirmanak.mealient.extensions.checkIfInputIsEmpty
|
||||||
import gq.kirmanak.mealient.logging.Logger
|
import gq.kirmanak.mealient.logging.Logger
|
||||||
|
import gq.kirmanak.mealient.ui.CheckableMenuItem
|
||||||
import gq.kirmanak.mealient.ui.OperationUiState
|
import gq.kirmanak.mealient.ui.OperationUiState
|
||||||
import gq.kirmanak.mealient.ui.activity.MainActivityViewModel
|
import gq.kirmanak.mealient.ui.activity.MainActivityViewModel
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@@ -32,7 +33,11 @@ class AuthenticationFragment : Fragment(R.layout.fragment_authentication) {
|
|||||||
logger.v { "onViewCreated() called with: view = $view, savedInstanceState = $savedInstanceState" }
|
logger.v { "onViewCreated() called with: view = $view, savedInstanceState = $savedInstanceState" }
|
||||||
binding.button.setOnClickListener { onLoginClicked() }
|
binding.button.setOnClickListener { onLoginClicked() }
|
||||||
activityViewModel.updateUiState {
|
activityViewModel.updateUiState {
|
||||||
it.copy(navigationVisible = true, searchVisible = false, checkedMenuItemId = R.id.login)
|
it.copy(
|
||||||
|
navigationVisible = true,
|
||||||
|
searchVisible = false,
|
||||||
|
checkedMenuItem = CheckableMenuItem.AddRecipe
|
||||||
|
)
|
||||||
}
|
}
|
||||||
viewModel.uiState.observe(viewLifecycleOwner, ::onUiStateChange)
|
viewModel.uiState.observe(viewLifecycleOwner, ::onUiStateChange)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import gq.kirmanak.mealient.databinding.FragmentBaseUrlBinding
|
|||||||
import gq.kirmanak.mealient.datasource.NetworkError
|
import gq.kirmanak.mealient.datasource.NetworkError
|
||||||
import gq.kirmanak.mealient.extensions.checkIfInputIsEmpty
|
import gq.kirmanak.mealient.extensions.checkIfInputIsEmpty
|
||||||
import gq.kirmanak.mealient.logging.Logger
|
import gq.kirmanak.mealient.logging.Logger
|
||||||
|
import gq.kirmanak.mealient.ui.CheckableMenuItem
|
||||||
import gq.kirmanak.mealient.ui.OperationUiState
|
import gq.kirmanak.mealient.ui.OperationUiState
|
||||||
import gq.kirmanak.mealient.ui.activity.MainActivityViewModel
|
import gq.kirmanak.mealient.ui.activity.MainActivityViewModel
|
||||||
import gq.kirmanak.mealient.ui.baseurl.BaseURLFragmentDirections.Companion.actionBaseURLFragmentToRecipesListFragment
|
import gq.kirmanak.mealient.ui.baseurl.BaseURLFragmentDirections.Companion.actionBaseURLFragmentToRecipesListFragment
|
||||||
@@ -39,7 +40,7 @@ class BaseURLFragment : Fragment(R.layout.fragment_base_url) {
|
|||||||
it.copy(
|
it.copy(
|
||||||
navigationVisible = !args.isOnboarding,
|
navigationVisible = !args.isOnboarding,
|
||||||
searchVisible = false,
|
searchVisible = false,
|
||||||
checkedMenuItemId = R.id.change_url,
|
checkedMenuItem = CheckableMenuItem.ChangeUrl,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import gq.kirmanak.mealient.data.baseurl.ServerInfoRepo
|
|||||||
import gq.kirmanak.mealient.data.recipes.RecipeRepo
|
import gq.kirmanak.mealient.data.recipes.RecipeRepo
|
||||||
import gq.kirmanak.mealient.datasource.NetworkError
|
import gq.kirmanak.mealient.datasource.NetworkError
|
||||||
import gq.kirmanak.mealient.logging.Logger
|
import gq.kirmanak.mealient.logging.Logger
|
||||||
|
import gq.kirmanak.mealient.shopping_lists.repo.ShoppingListsRepo
|
||||||
import gq.kirmanak.mealient.ui.OperationUiState
|
import gq.kirmanak.mealient.ui.OperationUiState
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@@ -20,6 +21,7 @@ class BaseURLViewModel @Inject constructor(
|
|||||||
private val authRepo: AuthRepo,
|
private val authRepo: AuthRepo,
|
||||||
private val recipeRepo: RecipeRepo,
|
private val recipeRepo: RecipeRepo,
|
||||||
private val logger: Logger,
|
private val logger: Logger,
|
||||||
|
private val shoppingListsRepo: ShoppingListsRepo,
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
private val _uiState = MutableLiveData<OperationUiState<Unit>>(OperationUiState.Initial())
|
private val _uiState = MutableLiveData<OperationUiState<Unit>>(OperationUiState.Initial())
|
||||||
|
|||||||
@@ -58,7 +58,11 @@ class DisclaimerFragment : Fragment(R.layout.fragment_disclaimer) {
|
|||||||
}
|
}
|
||||||
viewModel.startCountDown()
|
viewModel.startCountDown()
|
||||||
activityViewModel.updateUiState {
|
activityViewModel.updateUiState {
|
||||||
it.copy(navigationVisible = false, searchVisible = false, checkedMenuItemId = null)
|
it.copy(
|
||||||
|
navigationVisible = false,
|
||||||
|
searchVisible = false,
|
||||||
|
checkedMenuItem = null
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -17,11 +17,13 @@ import by.kirich1409.viewbindingdelegate.viewBinding
|
|||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import gq.kirmanak.mealient.R
|
import gq.kirmanak.mealient.R
|
||||||
|
import gq.kirmanak.mealient.architecture.valueUpdatesOnly
|
||||||
import gq.kirmanak.mealient.database.recipe.entity.RecipeSummaryEntity
|
import gq.kirmanak.mealient.database.recipe.entity.RecipeSummaryEntity
|
||||||
import gq.kirmanak.mealient.databinding.FragmentRecipesListBinding
|
import gq.kirmanak.mealient.databinding.FragmentRecipesListBinding
|
||||||
import gq.kirmanak.mealient.datasource.NetworkError
|
import gq.kirmanak.mealient.datasource.NetworkError
|
||||||
import gq.kirmanak.mealient.extensions.*
|
import gq.kirmanak.mealient.extensions.*
|
||||||
import gq.kirmanak.mealient.logging.Logger
|
import gq.kirmanak.mealient.logging.Logger
|
||||||
|
import gq.kirmanak.mealient.ui.CheckableMenuItem
|
||||||
import gq.kirmanak.mealient.ui.activity.MainActivityViewModel
|
import gq.kirmanak.mealient.ui.activity.MainActivityViewModel
|
||||||
import gq.kirmanak.mealient.ui.recipes.RecipesListFragmentDirections.Companion.actionRecipesFragmentToRecipeInfoFragment
|
import gq.kirmanak.mealient.ui.recipes.RecipesListFragmentDirections.Companion.actionRecipesFragmentToRecipeInfoFragment
|
||||||
import gq.kirmanak.mealient.ui.recipes.images.RecipePreloaderFactory
|
import gq.kirmanak.mealient.ui.recipes.images.RecipePreloaderFactory
|
||||||
@@ -54,7 +56,7 @@ class RecipesListFragment : Fragment(R.layout.fragment_recipes_list) {
|
|||||||
it.copy(
|
it.copy(
|
||||||
navigationVisible = true,
|
navigationVisible = true,
|
||||||
searchVisible = true,
|
searchVisible = true,
|
||||||
checkedMenuItemId = R.id.recipes_list
|
checkedMenuItem = CheckableMenuItem.RecipesList,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
collectWhenViewResumed(viewModel.showFavoriteIcon) { showFavoriteIcon ->
|
collectWhenViewResumed(viewModel.showFavoriteIcon) { showFavoriteIcon ->
|
||||||
|
|||||||
@@ -7,10 +7,10 @@ import androidx.lifecycle.viewModelScope
|
|||||||
import androidx.paging.PagingData
|
import androidx.paging.PagingData
|
||||||
import androidx.paging.cachedIn
|
import androidx.paging.cachedIn
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
|
import gq.kirmanak.mealient.architecture.valueUpdatesOnly
|
||||||
import gq.kirmanak.mealient.data.auth.AuthRepo
|
import gq.kirmanak.mealient.data.auth.AuthRepo
|
||||||
import gq.kirmanak.mealient.data.recipes.RecipeRepo
|
import gq.kirmanak.mealient.data.recipes.RecipeRepo
|
||||||
import gq.kirmanak.mealient.database.recipe.entity.RecipeSummaryEntity
|
import gq.kirmanak.mealient.database.recipe.entity.RecipeSummaryEntity
|
||||||
import gq.kirmanak.mealient.extensions.valueUpdatesOnly
|
|
||||||
import gq.kirmanak.mealient.logging.Logger
|
import gq.kirmanak.mealient.logging.Logger
|
||||||
import kotlinx.coroutines.channels.BufferOverflow
|
import kotlinx.coroutines.channels.BufferOverflow
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|||||||
@@ -12,6 +12,13 @@
|
|||||||
android:icon="@drawable/ic_add"
|
android:icon="@drawable/ic_add"
|
||||||
android:title="@string/menu_navigation_drawer_add_recipe" />
|
android:title="@string/menu_navigation_drawer_add_recipe" />
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/shopping_lists"
|
||||||
|
android:visible="false"
|
||||||
|
android:checkable="true"
|
||||||
|
android:icon="@drawable/ic_shopping_cart"
|
||||||
|
android:title="@string/menu_navigation_drawer_shopping_lists" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/change_url"
|
android:id="@+id/change_url"
|
||||||
android:checkable="true"
|
android:checkable="true"
|
||||||
|
|||||||
@@ -63,6 +63,11 @@
|
|||||||
android:label="fragment_add_recipe"
|
android:label="fragment_add_recipe"
|
||||||
tools:layout="@layout/fragment_add_recipe" />
|
tools:layout="@layout/fragment_add_recipe" />
|
||||||
|
|
||||||
|
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/shoppingListsFragment"
|
||||||
|
android:name="gq.kirmanak.mealient.shopping_lists.ui.ShoppingListsFragment" />
|
||||||
|
|
||||||
<action
|
<action
|
||||||
android:id="@+id/action_global_authenticationFragment"
|
android:id="@+id/action_global_authenticationFragment"
|
||||||
app:destination="@id/authenticationFragment" />
|
app:destination="@id/authenticationFragment" />
|
||||||
@@ -81,4 +86,9 @@
|
|||||||
android:id="@+id/action_global_baseURLFragment"
|
android:id="@+id/action_global_baseURLFragment"
|
||||||
app:destination="@id/baseURLFragment"
|
app:destination="@id/baseURLFragment"
|
||||||
app:popUpTo="@id/recipesListFragment" />
|
app:popUpTo="@id/recipesListFragment" />
|
||||||
|
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_global_shoppingListsFragment"
|
||||||
|
app:destination="@id/shoppingListsFragment"
|
||||||
|
app:popUpTo="@id/recipesListFragment" />
|
||||||
</navigation>
|
</navigation>
|
||||||
@@ -65,4 +65,5 @@
|
|||||||
<string name="view_holder_recipe_delete_content_description">Удалить рецепт</string>
|
<string name="view_holder_recipe_delete_content_description">Удалить рецепт</string>
|
||||||
<string name="fragment_recipes_favorite_added">%1$s добавлено в избранное</string>
|
<string name="fragment_recipes_favorite_added">%1$s добавлено в избранное</string>
|
||||||
<string name="fragment_recipes_favorite_removed">%1$s удалено из избранного</string>
|
<string name="fragment_recipes_favorite_removed">%1$s удалено из избранного</string>
|
||||||
|
<string name="menu_navigation_drawer_shopping_lists">Списки покупок</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -68,4 +68,5 @@
|
|||||||
<string name="view_holder_recipe_delete_content_description">Delete recipe</string>
|
<string name="view_holder_recipe_delete_content_description">Delete recipe</string>
|
||||||
<string name="fragment_recipes_favorite_added">Added %1$s to favorites</string>
|
<string name="fragment_recipes_favorite_added">Added %1$s to favorites</string>
|
||||||
<string name="fragment_recipes_favorite_removed">Removed %1$s from favorites</string>
|
<string name="fragment_recipes_favorite_removed">Removed %1$s from favorites</string>
|
||||||
|
<string name="menu_navigation_drawer_shopping_lists">Shopping lists</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -3,10 +3,12 @@ package gq.kirmanak.mealient.data.add.impl
|
|||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import gq.kirmanak.mealient.data.add.AddRecipeDataSource
|
import gq.kirmanak.mealient.data.add.AddRecipeDataSource
|
||||||
import gq.kirmanak.mealient.data.add.AddRecipeRepo
|
import gq.kirmanak.mealient.data.add.AddRecipeRepo
|
||||||
|
import gq.kirmanak.mealient.datasource_test.PORRIDGE_ADD_RECIPE_INFO
|
||||||
import gq.kirmanak.mealient.datastore.recipe.AddRecipeStorage
|
import gq.kirmanak.mealient.datastore.recipe.AddRecipeStorage
|
||||||
|
import gq.kirmanak.mealient.datastore_test.PORRIDGE_RECIPE_DRAFT
|
||||||
|
import gq.kirmanak.mealient.model_mapper.ModelMapper
|
||||||
|
import gq.kirmanak.mealient.model_mapper.ModelMapperImpl
|
||||||
import gq.kirmanak.mealient.test.BaseUnitTest
|
import gq.kirmanak.mealient.test.BaseUnitTest
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.PORRIDGE_ADD_RECIPE_INFO
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.PORRIDGE_RECIPE_DRAFT
|
|
||||||
import io.mockk.*
|
import io.mockk.*
|
||||||
import io.mockk.impl.annotations.MockK
|
import io.mockk.impl.annotations.MockK
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
@@ -24,12 +26,14 @@ class AddRecipeRepoTest : BaseUnitTest() {
|
|||||||
@MockK(relaxUnitFun = true)
|
@MockK(relaxUnitFun = true)
|
||||||
lateinit var storage: AddRecipeStorage
|
lateinit var storage: AddRecipeStorage
|
||||||
|
|
||||||
|
private val modelMapper: ModelMapper = ModelMapperImpl()
|
||||||
|
|
||||||
private lateinit var subject: AddRecipeRepo
|
private lateinit var subject: AddRecipeRepo
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
override fun setUp() {
|
override fun setUp() {
|
||||||
super.setUp()
|
super.setUp()
|
||||||
subject = AddRecipeRepoImpl(dataSource, storage, logger)
|
subject = AddRecipeRepoImpl(dataSource, storage, logger, modelMapper)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
package gq.kirmanak.mealient.data.baseurl
|
package gq.kirmanak.mealient.data.baseurl
|
||||||
|
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import gq.kirmanak.mealient.datasource.models.VersionInfo
|
||||||
|
import gq.kirmanak.mealient.datasource_test.VERSION_INFO_V0
|
||||||
import gq.kirmanak.mealient.test.AuthImplTestData.TEST_BASE_URL
|
import gq.kirmanak.mealient.test.AuthImplTestData.TEST_BASE_URL
|
||||||
import gq.kirmanak.mealient.test.AuthImplTestData.TEST_VERSION
|
import gq.kirmanak.mealient.test.AuthImplTestData.TEST_VERSION
|
||||||
import gq.kirmanak.mealient.test.BaseUnitTest
|
import gq.kirmanak.mealient.test.BaseUnitTest
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.VERSION_INFO_V0
|
|
||||||
import io.mockk.coEvery
|
import io.mockk.coEvery
|
||||||
import io.mockk.coVerify
|
import io.mockk.coVerify
|
||||||
import io.mockk.impl.annotations.MockK
|
import io.mockk.impl.annotations.MockK
|
||||||
|
|||||||
@@ -5,6 +5,18 @@ import gq.kirmanak.mealient.data.auth.AuthRepo
|
|||||||
import gq.kirmanak.mealient.data.baseurl.ServerInfoRepo
|
import gq.kirmanak.mealient.data.baseurl.ServerInfoRepo
|
||||||
import gq.kirmanak.mealient.datasource.v0.MealieDataSourceV0
|
import gq.kirmanak.mealient.datasource.v0.MealieDataSourceV0
|
||||||
import gq.kirmanak.mealient.datasource.v1.MealieDataSourceV1
|
import gq.kirmanak.mealient.datasource.v1.MealieDataSourceV1
|
||||||
|
import gq.kirmanak.mealient.datasource_test.PORRIDGE_ADD_RECIPE_INFO
|
||||||
|
import gq.kirmanak.mealient.datasource_test.PORRIDGE_ADD_RECIPE_REQUEST_V0
|
||||||
|
import gq.kirmanak.mealient.datasource_test.PORRIDGE_CREATE_RECIPE_REQUEST_V1
|
||||||
|
import gq.kirmanak.mealient.datasource_test.PORRIDGE_FULL_RECIPE_INFO
|
||||||
|
import gq.kirmanak.mealient.datasource_test.PORRIDGE_RECIPE_RESPONSE_V1
|
||||||
|
import gq.kirmanak.mealient.datasource_test.PORRIDGE_RECIPE_SUMMARY_RESPONSE_V0
|
||||||
|
import gq.kirmanak.mealient.datasource_test.PORRIDGE_RECIPE_SUMMARY_RESPONSE_V1
|
||||||
|
import gq.kirmanak.mealient.datasource_test.PORRIDGE_UPDATE_RECIPE_REQUEST_V1
|
||||||
|
import gq.kirmanak.mealient.datasource_test.RECIPE_SUMMARY_PORRIDGE_V0
|
||||||
|
import gq.kirmanak.mealient.datasource_test.RECIPE_SUMMARY_PORRIDGE_V1
|
||||||
|
import gq.kirmanak.mealient.model_mapper.ModelMapper
|
||||||
|
import gq.kirmanak.mealient.model_mapper.ModelMapperImpl
|
||||||
import gq.kirmanak.mealient.test.AuthImplTestData.FAVORITE_RECIPES_LIST
|
import gq.kirmanak.mealient.test.AuthImplTestData.FAVORITE_RECIPES_LIST
|
||||||
import gq.kirmanak.mealient.test.AuthImplTestData.TEST_AUTH_HEADER
|
import gq.kirmanak.mealient.test.AuthImplTestData.TEST_AUTH_HEADER
|
||||||
import gq.kirmanak.mealient.test.AuthImplTestData.TEST_SERVER_VERSION_V0
|
import gq.kirmanak.mealient.test.AuthImplTestData.TEST_SERVER_VERSION_V0
|
||||||
@@ -12,16 +24,6 @@ import gq.kirmanak.mealient.test.AuthImplTestData.TEST_SERVER_VERSION_V1
|
|||||||
import gq.kirmanak.mealient.test.AuthImplTestData.USER_INFO_V0
|
import gq.kirmanak.mealient.test.AuthImplTestData.USER_INFO_V0
|
||||||
import gq.kirmanak.mealient.test.AuthImplTestData.USER_INFO_V1
|
import gq.kirmanak.mealient.test.AuthImplTestData.USER_INFO_V1
|
||||||
import gq.kirmanak.mealient.test.BaseUnitTest
|
import gq.kirmanak.mealient.test.BaseUnitTest
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.PORRIDGE_ADD_RECIPE_INFO
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.PORRIDGE_ADD_RECIPE_REQUEST_V0
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.PORRIDGE_CREATE_RECIPE_REQUEST_V1
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.PORRIDGE_FULL_RECIPE_INFO
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.PORRIDGE_RECIPE_RESPONSE_V1
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.PORRIDGE_RECIPE_SUMMARY_RESPONSE_V0
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.PORRIDGE_RECIPE_SUMMARY_RESPONSE_V1
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.PORRIDGE_UPDATE_RECIPE_REQUEST_V1
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.RECIPE_SUMMARY_PORRIDGE_V0
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.RECIPE_SUMMARY_PORRIDGE_V1
|
|
||||||
import io.mockk.*
|
import io.mockk.*
|
||||||
import io.mockk.impl.annotations.MockK
|
import io.mockk.impl.annotations.MockK
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
@@ -45,12 +47,14 @@ class MealieDataSourceWrapperTest : BaseUnitTest() {
|
|||||||
@MockK(relaxUnitFun = true)
|
@MockK(relaxUnitFun = true)
|
||||||
lateinit var v1Source: MealieDataSourceV1
|
lateinit var v1Source: MealieDataSourceV1
|
||||||
|
|
||||||
|
private val modelMapper: ModelMapper = ModelMapperImpl()
|
||||||
|
|
||||||
lateinit var subject: MealieDataSourceWrapper
|
lateinit var subject: MealieDataSourceWrapper
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
override fun setUp() {
|
override fun setUp() {
|
||||||
super.setUp()
|
super.setUp()
|
||||||
subject = MealieDataSourceWrapper(serverInfoRepo, v0Source, v1Source)
|
subject = MealieDataSourceWrapper(serverInfoRepo, v0Source, v1Source, modelMapper)
|
||||||
coEvery { v0Source.requestUserInfo() } returns USER_INFO_V0
|
coEvery { v0Source.requestUserInfo() } returns USER_INFO_V0
|
||||||
coEvery { v1Source.requestUserInfo() } returns USER_INFO_V1
|
coEvery { v1Source.requestUserInfo() } returns USER_INFO_V1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,97 +0,0 @@
|
|||||||
package gq.kirmanak.mealient.data.recipes.db
|
|
||||||
|
|
||||||
import com.google.common.truth.Truth.assertThat
|
|
||||||
import dagger.hilt.android.testing.HiltAndroidTest
|
|
||||||
import gq.kirmanak.mealient.database.AppDb
|
|
||||||
import gq.kirmanak.mealient.test.HiltRobolectricTest
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.BREAD_INGREDIENT
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.CAKE_BREAD_RECIPE_INGREDIENT_ENTITY
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.CAKE_FULL_RECIPE_INFO
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.CAKE_RECIPE_SUMMARY_ENTITY
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.FULL_CAKE_INFO_ENTITY
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.FULL_PORRIDGE_INFO_ENTITY
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.MIX_CAKE_RECIPE_INSTRUCTION_ENTITY
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.MIX_INSTRUCTION
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.PORRIDGE_FULL_RECIPE_INFO
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.PORRIDGE_RECIPE_SUMMARY_ENTITY
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.TEST_RECIPE_SUMMARY_ENTITIES
|
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
|
||||||
import kotlinx.coroutines.test.runTest
|
|
||||||
import org.junit.Test
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
@HiltAndroidTest
|
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
|
||||||
class RecipeStorageImplTest : HiltRobolectricTest() {
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
lateinit var subject: RecipeStorageImpl
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
lateinit var appDb: AppDb
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `when saveRecipes then saves recipes`() = runTest {
|
|
||||||
subject.saveRecipes(TEST_RECIPE_SUMMARY_ENTITIES)
|
|
||||||
val actualTags = appDb.recipeDao().queryAllRecipes()
|
|
||||||
assertThat(actualTags).containsExactly(
|
|
||||||
CAKE_RECIPE_SUMMARY_ENTITY,
|
|
||||||
PORRIDGE_RECIPE_SUMMARY_ENTITY
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `when refreshAll then old recipes aren't preserved`() = runTest {
|
|
||||||
subject.saveRecipes(TEST_RECIPE_SUMMARY_ENTITIES)
|
|
||||||
subject.refreshAll(listOf(CAKE_RECIPE_SUMMARY_ENTITY))
|
|
||||||
val actual = appDb.recipeDao().queryAllRecipes()
|
|
||||||
assertThat(actual).containsExactly(CAKE_RECIPE_SUMMARY_ENTITY)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `when clearAllLocalData then recipes aren't preserved`() = runTest {
|
|
||||||
subject.saveRecipes(TEST_RECIPE_SUMMARY_ENTITIES)
|
|
||||||
subject.clearAllLocalData()
|
|
||||||
val actual = appDb.recipeDao().queryAllRecipes()
|
|
||||||
assertThat(actual).isEmpty()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `when saveRecipeInfo then saves recipe info`() = runTest {
|
|
||||||
subject.saveRecipes(listOf(CAKE_RECIPE_SUMMARY_ENTITY))
|
|
||||||
subject.saveRecipeInfo(CAKE_FULL_RECIPE_INFO)
|
|
||||||
val actual = appDb.recipeDao().queryFullRecipeInfo("1")
|
|
||||||
assertThat(actual).isEqualTo(FULL_CAKE_INFO_ENTITY)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `when saveRecipeInfo with two then saves second`() = runTest {
|
|
||||||
subject.saveRecipes(TEST_RECIPE_SUMMARY_ENTITIES)
|
|
||||||
subject.saveRecipeInfo(CAKE_FULL_RECIPE_INFO)
|
|
||||||
subject.saveRecipeInfo(PORRIDGE_FULL_RECIPE_INFO)
|
|
||||||
val actual = appDb.recipeDao().queryFullRecipeInfo("2")
|
|
||||||
assertThat(actual).isEqualTo(FULL_PORRIDGE_INFO_ENTITY)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `when saveRecipeInfo secondly then overwrites ingredients`() = runTest {
|
|
||||||
subject.saveRecipes(listOf(CAKE_RECIPE_SUMMARY_ENTITY))
|
|
||||||
subject.saveRecipeInfo(CAKE_FULL_RECIPE_INFO)
|
|
||||||
val newRecipe = CAKE_FULL_RECIPE_INFO.copy(recipeIngredients = listOf(BREAD_INGREDIENT))
|
|
||||||
subject.saveRecipeInfo(newRecipe)
|
|
||||||
val actual = appDb.recipeDao().queryFullRecipeInfo("1")?.recipeIngredients
|
|
||||||
val expected = listOf(CAKE_BREAD_RECIPE_INGREDIENT_ENTITY.copy(localId = 3))
|
|
||||||
assertThat(actual).isEqualTo(expected)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `when saveRecipeInfo secondly then overwrites instructions`() = runTest {
|
|
||||||
subject.saveRecipes(listOf(CAKE_RECIPE_SUMMARY_ENTITY))
|
|
||||||
subject.saveRecipeInfo(CAKE_FULL_RECIPE_INFO)
|
|
||||||
val newRecipe = CAKE_FULL_RECIPE_INFO.copy(recipeInstructions = listOf(MIX_INSTRUCTION))
|
|
||||||
subject.saveRecipeInfo(newRecipe)
|
|
||||||
val actual = appDb.recipeDao().queryFullRecipeInfo("1")?.recipeInstructions
|
|
||||||
val expected = listOf(MIX_CAKE_RECIPE_INSTRUCTION_ENTITY.copy(localId = 3))
|
|
||||||
assertThat(actual).isEqualTo(expected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,12 +3,12 @@ package gq.kirmanak.mealient.data.recipes.impl
|
|||||||
import androidx.paging.PagingSource
|
import androidx.paging.PagingSource
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import dagger.hilt.android.testing.HiltAndroidTest
|
import dagger.hilt.android.testing.HiltAndroidTest
|
||||||
import gq.kirmanak.mealient.data.recipes.db.RecipeStorage
|
import gq.kirmanak.mealient.database.CAKE_RECIPE_SUMMARY_ENTITY
|
||||||
|
import gq.kirmanak.mealient.database.PORRIDGE_RECIPE_SUMMARY_ENTITY
|
||||||
|
import gq.kirmanak.mealient.database.TEST_RECIPE_SUMMARY_ENTITIES
|
||||||
|
import gq.kirmanak.mealient.database.recipe.RecipeStorage
|
||||||
import gq.kirmanak.mealient.database.recipe.entity.RecipeSummaryEntity
|
import gq.kirmanak.mealient.database.recipe.entity.RecipeSummaryEntity
|
||||||
import gq.kirmanak.mealient.test.HiltRobolectricTest
|
import gq.kirmanak.mealient.test.HiltRobolectricTest
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.CAKE_RECIPE_SUMMARY_ENTITY
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.PORRIDGE_RECIPE_SUMMARY_ENTITY
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.TEST_RECIPE_SUMMARY_ENTITIES
|
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|||||||
@@ -3,13 +3,20 @@ package gq.kirmanak.mealient.data.recipes.impl
|
|||||||
import androidx.paging.LoadType
|
import androidx.paging.LoadType
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import gq.kirmanak.mealient.data.recipes.RecipeRepo
|
import gq.kirmanak.mealient.data.recipes.RecipeRepo
|
||||||
import gq.kirmanak.mealient.data.recipes.db.RecipeStorage
|
|
||||||
import gq.kirmanak.mealient.data.recipes.network.RecipeDataSource
|
import gq.kirmanak.mealient.data.recipes.network.RecipeDataSource
|
||||||
|
import gq.kirmanak.mealient.database.BAKE_CAKE_RECIPE_INSTRUCTION_ENTITY
|
||||||
|
import gq.kirmanak.mealient.database.CAKE_BREAD_RECIPE_INGREDIENT_ENTITY
|
||||||
|
import gq.kirmanak.mealient.database.CAKE_RECIPE_ENTITY
|
||||||
|
import gq.kirmanak.mealient.database.CAKE_RECIPE_SUMMARY_ENTITY
|
||||||
|
import gq.kirmanak.mealient.database.CAKE_SUGAR_RECIPE_INGREDIENT_ENTITY
|
||||||
|
import gq.kirmanak.mealient.database.FULL_CAKE_INFO_ENTITY
|
||||||
|
import gq.kirmanak.mealient.database.MIX_CAKE_RECIPE_INSTRUCTION_ENTITY
|
||||||
|
import gq.kirmanak.mealient.database.recipe.RecipeStorage
|
||||||
import gq.kirmanak.mealient.datasource.NetworkError.Unauthorized
|
import gq.kirmanak.mealient.datasource.NetworkError.Unauthorized
|
||||||
|
import gq.kirmanak.mealient.datasource_test.CAKE_FULL_RECIPE_INFO
|
||||||
|
import gq.kirmanak.mealient.model_mapper.ModelMapper
|
||||||
|
import gq.kirmanak.mealient.model_mapper.ModelMapperImpl
|
||||||
import gq.kirmanak.mealient.test.BaseUnitTest
|
import gq.kirmanak.mealient.test.BaseUnitTest
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.CAKE_FULL_RECIPE_INFO
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.CAKE_RECIPE_SUMMARY_ENTITY
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.FULL_CAKE_INFO_ENTITY
|
|
||||||
import io.mockk.coEvery
|
import io.mockk.coEvery
|
||||||
import io.mockk.coVerify
|
import io.mockk.coVerify
|
||||||
import io.mockk.coVerifyOrder
|
import io.mockk.coVerifyOrder
|
||||||
@@ -36,12 +43,21 @@ class RecipeRepoTest : BaseUnitTest() {
|
|||||||
@MockK(relaxUnitFun = true)
|
@MockK(relaxUnitFun = true)
|
||||||
lateinit var pagingSourceFactory: RecipePagingSourceFactory
|
lateinit var pagingSourceFactory: RecipePagingSourceFactory
|
||||||
|
|
||||||
|
private val modelMapper: ModelMapper = ModelMapperImpl()
|
||||||
|
|
||||||
lateinit var subject: RecipeRepo
|
lateinit var subject: RecipeRepo
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
override fun setUp() {
|
override fun setUp() {
|
||||||
super.setUp()
|
super.setUp()
|
||||||
subject = RecipeRepoImpl(remoteMediator, storage, pagingSourceFactory, dataSource, logger)
|
subject = RecipeRepoImpl(
|
||||||
|
remoteMediator,
|
||||||
|
storage,
|
||||||
|
pagingSourceFactory,
|
||||||
|
dataSource,
|
||||||
|
logger,
|
||||||
|
modelMapper,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -55,7 +71,18 @@ class RecipeRepoTest : BaseUnitTest() {
|
|||||||
fun `when refreshRecipeInfo expect call to storage`() = runTest {
|
fun `when refreshRecipeInfo expect call to storage`() = runTest {
|
||||||
coEvery { dataSource.requestRecipeInfo(eq("cake")) } returns CAKE_FULL_RECIPE_INFO
|
coEvery { dataSource.requestRecipeInfo(eq("cake")) } returns CAKE_FULL_RECIPE_INFO
|
||||||
subject.refreshRecipeInfo("cake")
|
subject.refreshRecipeInfo("cake")
|
||||||
coVerify { storage.saveRecipeInfo(eq(CAKE_FULL_RECIPE_INFO)) }
|
coVerify {
|
||||||
|
storage.saveRecipeInfo(
|
||||||
|
eq(CAKE_RECIPE_ENTITY),
|
||||||
|
eq(
|
||||||
|
listOf(
|
||||||
|
CAKE_SUGAR_RECIPE_INGREDIENT_ENTITY,
|
||||||
|
CAKE_BREAD_RECIPE_INGREDIENT_ENTITY
|
||||||
|
)
|
||||||
|
),
|
||||||
|
eq(listOf(MIX_CAKE_RECIPE_INSTRUCTION_ENTITY, BAKE_CAKE_RECIPE_INSTRUCTION_ENTITY))
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -3,13 +3,15 @@ package gq.kirmanak.mealient.data.recipes.impl
|
|||||||
import androidx.paging.*
|
import androidx.paging.*
|
||||||
import androidx.paging.LoadType.*
|
import androidx.paging.LoadType.*
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import gq.kirmanak.mealient.data.recipes.db.RecipeStorage
|
|
||||||
import gq.kirmanak.mealient.data.recipes.network.RecipeDataSource
|
import gq.kirmanak.mealient.data.recipes.network.RecipeDataSource
|
||||||
|
import gq.kirmanak.mealient.database.TEST_RECIPE_SUMMARY_ENTITIES
|
||||||
|
import gq.kirmanak.mealient.database.recipe.RecipeStorage
|
||||||
import gq.kirmanak.mealient.database.recipe.entity.RecipeSummaryEntity
|
import gq.kirmanak.mealient.database.recipe.entity.RecipeSummaryEntity
|
||||||
import gq.kirmanak.mealient.datasource.NetworkError.Unauthorized
|
import gq.kirmanak.mealient.datasource.NetworkError.Unauthorized
|
||||||
|
import gq.kirmanak.mealient.datasource_test.TEST_RECIPE_SUMMARIES
|
||||||
|
import gq.kirmanak.mealient.model_mapper.ModelMapper
|
||||||
|
import gq.kirmanak.mealient.model_mapper.ModelMapperImpl
|
||||||
import gq.kirmanak.mealient.test.BaseUnitTest
|
import gq.kirmanak.mealient.test.BaseUnitTest
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.TEST_RECIPE_SUMMARIES
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.TEST_RECIPE_SUMMARY_ENTITIES
|
|
||||||
import io.mockk.coEvery
|
import io.mockk.coEvery
|
||||||
import io.mockk.coVerify
|
import io.mockk.coVerify
|
||||||
import io.mockk.impl.annotations.MockK
|
import io.mockk.impl.annotations.MockK
|
||||||
@@ -41,6 +43,8 @@ class RecipesRemoteMediatorTest : BaseUnitTest() {
|
|||||||
@MockK(relaxUnitFun = true)
|
@MockK(relaxUnitFun = true)
|
||||||
lateinit var pagingSourceFactory: RecipePagingSourceFactory
|
lateinit var pagingSourceFactory: RecipePagingSourceFactory
|
||||||
|
|
||||||
|
private val modelMapper: ModelMapper = ModelMapperImpl()
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
override fun setUp() {
|
override fun setUp() {
|
||||||
super.setUp()
|
super.setUp()
|
||||||
@@ -50,6 +54,7 @@ class RecipesRemoteMediatorTest : BaseUnitTest() {
|
|||||||
pagingSourceFactory = pagingSourceFactory,
|
pagingSourceFactory = pagingSourceFactory,
|
||||||
logger = logger,
|
logger = logger,
|
||||||
dispatchers = dispatchers,
|
dispatchers = dispatchers,
|
||||||
|
modelMapper = modelMapper,
|
||||||
)
|
)
|
||||||
coEvery { dataSource.getFavoriteRecipes() } returns emptyList()
|
coEvery { dataSource.getFavoriteRecipes() } returns emptyList()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package gq.kirmanak.mealient.data.share
|
package gq.kirmanak.mealient.data.share
|
||||||
|
|
||||||
|
import gq.kirmanak.mealient.datasource.models.ParseRecipeURLInfo
|
||||||
import gq.kirmanak.mealient.test.BaseUnitTest
|
import gq.kirmanak.mealient.test.BaseUnitTest
|
||||||
import io.mockk.coEvery
|
import io.mockk.coEvery
|
||||||
import io.mockk.coVerify
|
import io.mockk.coVerify
|
||||||
|
|||||||
@@ -1,146 +0,0 @@
|
|||||||
package gq.kirmanak.mealient.extensions
|
|
||||||
|
|
||||||
import com.google.common.truth.Truth.assertThat
|
|
||||||
import gq.kirmanak.mealient.test.BaseUnitTest
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.CAKE_FULL_RECIPE_INFO
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.CAKE_RECIPE_ENTITY
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.CAKE_SUGAR_RECIPE_INGREDIENT_ENTITY
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.MILK_RECIPE_INGREDIENT_INFO
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.MILK_RECIPE_INGREDIENT_RESPONSE_V0
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.MILK_RECIPE_INGREDIENT_RESPONSE_V1
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.MIX_CAKE_RECIPE_INSTRUCTION_ENTITY
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.MIX_INSTRUCTION
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.MIX_RECIPE_INSTRUCTION_INFO
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.MIX_RECIPE_INSTRUCTION_RESPONSE_V0
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.MIX_RECIPE_INSTRUCTION_RESPONSE_V1
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.PORRIDGE_ADD_RECIPE_INFO
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.PORRIDGE_ADD_RECIPE_REQUEST_V0
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.PORRIDGE_CREATE_RECIPE_REQUEST_V1
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.PORRIDGE_FULL_RECIPE_INFO
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.PORRIDGE_RECIPE_DRAFT
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.PORRIDGE_RECIPE_RESPONSE_V0
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.PORRIDGE_RECIPE_RESPONSE_V1
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.PORRIDGE_RECIPE_SUMMARY_ENTITY
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.PORRIDGE_RECIPE_SUMMARY_RESPONSE_V0
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.PORRIDGE_RECIPE_SUMMARY_RESPONSE_V1
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.PORRIDGE_UPDATE_RECIPE_REQUEST_V1
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.RECIPE_SUMMARY_PORRIDGE_V0
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.RECIPE_SUMMARY_PORRIDGE_V1
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.SUGAR_INGREDIENT
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.VERSION_INFO_V0
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.VERSION_INFO_V1
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.VERSION_RESPONSE_V0
|
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.VERSION_RESPONSE_V1
|
|
||||||
import org.junit.Test
|
|
||||||
|
|
||||||
class ModelMappingsTest : BaseUnitTest() {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `when toAddRecipeRequest then fills fields correctly`() {
|
|
||||||
assertThat(PORRIDGE_RECIPE_DRAFT.toAddRecipeInfo()).isEqualTo(PORRIDGE_ADD_RECIPE_INFO)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `when toDraft then fills fields correctly`() {
|
|
||||||
assertThat(PORRIDGE_ADD_RECIPE_INFO.toDraft()).isEqualTo(PORRIDGE_RECIPE_DRAFT)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `when full recipe info to entity expect correct entity`() {
|
|
||||||
assertThat(CAKE_FULL_RECIPE_INFO.toRecipeEntity()).isEqualTo(CAKE_RECIPE_ENTITY)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `when ingredient info to entity expect correct entity`() {
|
|
||||||
val actual = SUGAR_INGREDIENT.toRecipeIngredientEntity("1")
|
|
||||||
assertThat(actual).isEqualTo(CAKE_SUGAR_RECIPE_INGREDIENT_ENTITY)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `when instruction info to entity expect correct entity`() {
|
|
||||||
val actual = MIX_INSTRUCTION.toRecipeInstructionEntity("1")
|
|
||||||
assertThat(actual).isEqualTo(MIX_CAKE_RECIPE_INSTRUCTION_ENTITY)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `when summary v0 to info expect correct info`() {
|
|
||||||
val actual = PORRIDGE_RECIPE_SUMMARY_RESPONSE_V0.toRecipeSummaryInfo()
|
|
||||||
assertThat(actual).isEqualTo(RECIPE_SUMMARY_PORRIDGE_V0)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `when summary v1 to info expect correct info`() {
|
|
||||||
val actual = PORRIDGE_RECIPE_SUMMARY_RESPONSE_V1.toRecipeSummaryInfo()
|
|
||||||
assertThat(actual).isEqualTo(RECIPE_SUMMARY_PORRIDGE_V1)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `when summary info to entity expect correct entity`() {
|
|
||||||
val actual = RECIPE_SUMMARY_PORRIDGE_V0.toRecipeSummaryEntity(isFavorite = false)
|
|
||||||
assertThat(actual).isEqualTo(PORRIDGE_RECIPE_SUMMARY_ENTITY)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `when version response v0 to info expect correct info`() {
|
|
||||||
assertThat(VERSION_RESPONSE_V0.toVersionInfo()).isEqualTo(VERSION_INFO_V0)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `when version response v1 to info expect correct info`() {
|
|
||||||
assertThat(VERSION_RESPONSE_V1.toVersionInfo()).isEqualTo(VERSION_INFO_V1)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `when recipe ingredient response v0 to info expect correct info`() {
|
|
||||||
val actual = MILK_RECIPE_INGREDIENT_RESPONSE_V0.toRecipeIngredientInfo()
|
|
||||||
assertThat(actual).isEqualTo(MILK_RECIPE_INGREDIENT_INFO)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `when recipe ingredient response v1 to info expect correct info`() {
|
|
||||||
val actual = MILK_RECIPE_INGREDIENT_RESPONSE_V1.toRecipeIngredientInfo()
|
|
||||||
assertThat(actual).isEqualTo(MILK_RECIPE_INGREDIENT_INFO)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `when recipe instruction response v0 to info expect correct info`() {
|
|
||||||
val actual = MIX_RECIPE_INSTRUCTION_RESPONSE_V0.toRecipeInstructionInfo()
|
|
||||||
assertThat(actual).isEqualTo(MIX_RECIPE_INSTRUCTION_INFO)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `when recipe instruction response v1 to info expect correct info`() {
|
|
||||||
val actual = MIX_RECIPE_INSTRUCTION_RESPONSE_V1.toRecipeInstructionInfo()
|
|
||||||
assertThat(actual).isEqualTo(MIX_RECIPE_INSTRUCTION_INFO)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `when recipe response v0 to info expect correct info`() {
|
|
||||||
val actual = PORRIDGE_RECIPE_RESPONSE_V0.toFullRecipeInfo()
|
|
||||||
assertThat(actual).isEqualTo(PORRIDGE_FULL_RECIPE_INFO)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `when recipe response v1 to info expect correct info`() {
|
|
||||||
val actual = PORRIDGE_RECIPE_RESPONSE_V1.toFullRecipeInfo()
|
|
||||||
assertThat(actual).isEqualTo(PORRIDGE_FULL_RECIPE_INFO)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `when add recipe info to request v0 expect correct request`() {
|
|
||||||
val actual = PORRIDGE_ADD_RECIPE_INFO.toV0Request()
|
|
||||||
assertThat(actual).isEqualTo(PORRIDGE_ADD_RECIPE_REQUEST_V0)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `when add recipe info to create request v1 expect correct request`() {
|
|
||||||
val actual = PORRIDGE_ADD_RECIPE_INFO.toV1CreateRequest()
|
|
||||||
assertThat(actual).isEqualTo(PORRIDGE_CREATE_RECIPE_REQUEST_V1)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `when add recipe info to update request v1 expect correct request`() {
|
|
||||||
val actual = PORRIDGE_ADD_RECIPE_INFO.toV1UpdateRequest()
|
|
||||||
assertThat(actual).isEqualTo(PORRIDGE_UPDATE_RECIPE_REQUEST_V1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,440 +0,0 @@
|
|||||||
package gq.kirmanak.mealient.test
|
|
||||||
|
|
||||||
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.data.baseurl.VersionInfo
|
|
||||||
import gq.kirmanak.mealient.data.recipes.network.FullRecipeInfo
|
|
||||||
import gq.kirmanak.mealient.data.recipes.network.RecipeIngredientInfo
|
|
||||||
import gq.kirmanak.mealient.data.recipes.network.RecipeInstructionInfo
|
|
||||||
import gq.kirmanak.mealient.data.recipes.network.RecipeSettingsInfo
|
|
||||||
import gq.kirmanak.mealient.data.recipes.network.RecipeSummaryInfo
|
|
||||||
import gq.kirmanak.mealient.database.recipe.entity.FullRecipeEntity
|
|
||||||
import gq.kirmanak.mealient.database.recipe.entity.RecipeEntity
|
|
||||||
import gq.kirmanak.mealient.database.recipe.entity.RecipeIngredientEntity
|
|
||||||
import gq.kirmanak.mealient.database.recipe.entity.RecipeInstructionEntity
|
|
||||||
import gq.kirmanak.mealient.database.recipe.entity.RecipeSummaryEntity
|
|
||||||
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.datasource.v0.models.GetRecipeIngredientResponseV0
|
|
||||||
import gq.kirmanak.mealient.datasource.v0.models.GetRecipeInstructionResponseV0
|
|
||||||
import gq.kirmanak.mealient.datasource.v0.models.GetRecipeResponseV0
|
|
||||||
import gq.kirmanak.mealient.datasource.v0.models.GetRecipeSummaryResponseV0
|
|
||||||
import gq.kirmanak.mealient.datasource.v0.models.VersionResponseV0
|
|
||||||
import gq.kirmanak.mealient.datasource.v1.models.AddRecipeIngredientV1
|
|
||||||
import gq.kirmanak.mealient.datasource.v1.models.AddRecipeInstructionV1
|
|
||||||
import gq.kirmanak.mealient.datasource.v1.models.AddRecipeSettingsV1
|
|
||||||
import gq.kirmanak.mealient.datasource.v1.models.CreateRecipeRequestV1
|
|
||||||
import gq.kirmanak.mealient.datasource.v1.models.GetRecipeIngredientResponseV1
|
|
||||||
import gq.kirmanak.mealient.datasource.v1.models.GetRecipeInstructionResponseV1
|
|
||||||
import gq.kirmanak.mealient.datasource.v1.models.GetRecipeResponseV1
|
|
||||||
import gq.kirmanak.mealient.datasource.v1.models.GetRecipeSettingsResponseV1
|
|
||||||
import gq.kirmanak.mealient.datasource.v1.models.GetRecipeSummaryResponseV1
|
|
||||||
import gq.kirmanak.mealient.datasource.v1.models.UpdateRecipeRequestV1
|
|
||||||
import gq.kirmanak.mealient.datasource.v1.models.VersionResponseV1
|
|
||||||
import gq.kirmanak.mealient.datastore.recipe.AddRecipeDraft
|
|
||||||
import kotlinx.datetime.LocalDate
|
|
||||||
import kotlinx.datetime.LocalDateTime
|
|
||||||
|
|
||||||
object RecipeImplTestData {
|
|
||||||
val RECIPE_SUMMARY_CAKE = RecipeSummaryInfo(
|
|
||||||
remoteId = "1",
|
|
||||||
name = "Cake",
|
|
||||||
slug = "cake",
|
|
||||||
description = "A tasty cake",
|
|
||||||
dateAdded = LocalDate.parse("2021-11-13"),
|
|
||||||
dateUpdated = LocalDateTime.parse("2021-11-13T15:30:13"),
|
|
||||||
imageId = "cake",
|
|
||||||
)
|
|
||||||
|
|
||||||
val RECIPE_SUMMARY_PORRIDGE_V0 = RecipeSummaryInfo(
|
|
||||||
remoteId = "2",
|
|
||||||
name = "Porridge",
|
|
||||||
slug = "porridge",
|
|
||||||
description = "A tasty porridge",
|
|
||||||
dateAdded = LocalDate.parse("2021-11-12"),
|
|
||||||
dateUpdated = LocalDateTime.parse("2021-10-13T17:35:23"),
|
|
||||||
imageId = "porridge",
|
|
||||||
)
|
|
||||||
|
|
||||||
val RECIPE_SUMMARY_PORRIDGE_V1 = RecipeSummaryInfo(
|
|
||||||
remoteId = "2",
|
|
||||||
name = "Porridge",
|
|
||||||
slug = "porridge",
|
|
||||||
description = "A tasty porridge",
|
|
||||||
dateAdded = LocalDate.parse("2021-11-12"),
|
|
||||||
dateUpdated = LocalDateTime.parse("2021-10-13T17:35:23"),
|
|
||||||
imageId = "2",
|
|
||||||
)
|
|
||||||
|
|
||||||
val TEST_RECIPE_SUMMARIES = listOf(RECIPE_SUMMARY_CAKE, RECIPE_SUMMARY_PORRIDGE_V0)
|
|
||||||
|
|
||||||
val CAKE_RECIPE_SUMMARY_ENTITY = RecipeSummaryEntity(
|
|
||||||
remoteId = "1",
|
|
||||||
name = "Cake",
|
|
||||||
slug = "cake",
|
|
||||||
description = "A tasty cake",
|
|
||||||
dateAdded = LocalDate.parse("2021-11-13"),
|
|
||||||
dateUpdated = LocalDateTime.parse("2021-11-13T15:30:13"),
|
|
||||||
imageId = "cake",
|
|
||||||
isFavorite = false,
|
|
||||||
)
|
|
||||||
|
|
||||||
val PORRIDGE_RECIPE_SUMMARY_ENTITY = RecipeSummaryEntity(
|
|
||||||
remoteId = "2",
|
|
||||||
name = "Porridge",
|
|
||||||
slug = "porridge",
|
|
||||||
description = "A tasty porridge",
|
|
||||||
dateAdded = LocalDate.parse("2021-11-12"),
|
|
||||||
dateUpdated = LocalDateTime.parse("2021-10-13T17:35:23"),
|
|
||||||
imageId = "porridge",
|
|
||||||
isFavorite = false,
|
|
||||||
)
|
|
||||||
|
|
||||||
val TEST_RECIPE_SUMMARY_ENTITIES =
|
|
||||||
listOf(CAKE_RECIPE_SUMMARY_ENTITY, PORRIDGE_RECIPE_SUMMARY_ENTITY)
|
|
||||||
|
|
||||||
val SUGAR_INGREDIENT = RecipeIngredientInfo(
|
|
||||||
note = "2 oz of white sugar",
|
|
||||||
quantity = 1.0,
|
|
||||||
unit = null,
|
|
||||||
food = null,
|
|
||||||
title = null,
|
|
||||||
)
|
|
||||||
|
|
||||||
val BREAD_INGREDIENT = RecipeIngredientInfo(
|
|
||||||
note = "2 oz of white bread",
|
|
||||||
quantity = 1.0,
|
|
||||||
unit = null,
|
|
||||||
food = null,
|
|
||||||
title = null,
|
|
||||||
)
|
|
||||||
|
|
||||||
private val MILK_INGREDIENT = RecipeIngredientInfo(
|
|
||||||
note = "2 oz of white milk",
|
|
||||||
quantity = 1.0,
|
|
||||||
unit = null,
|
|
||||||
food = null,
|
|
||||||
title = null,
|
|
||||||
)
|
|
||||||
|
|
||||||
val MIX_INSTRUCTION = RecipeInstructionInfo(
|
|
||||||
text = "Mix the ingredients"
|
|
||||||
)
|
|
||||||
|
|
||||||
private val BAKE_INSTRUCTION = RecipeInstructionInfo(
|
|
||||||
text = "Bake the ingredients"
|
|
||||||
)
|
|
||||||
|
|
||||||
private val BOIL_INSTRUCTION = RecipeInstructionInfo(
|
|
||||||
text = "Boil the ingredients"
|
|
||||||
)
|
|
||||||
|
|
||||||
val CAKE_FULL_RECIPE_INFO = FullRecipeInfo(
|
|
||||||
remoteId = "1",
|
|
||||||
name = "Cake",
|
|
||||||
recipeYield = "4 servings",
|
|
||||||
recipeIngredients = listOf(SUGAR_INGREDIENT, BREAD_INGREDIENT),
|
|
||||||
recipeInstructions = listOf(MIX_INSTRUCTION, BAKE_INSTRUCTION),
|
|
||||||
settings = RecipeSettingsInfo(disableAmounts = true)
|
|
||||||
)
|
|
||||||
|
|
||||||
val PORRIDGE_FULL_RECIPE_INFO = FullRecipeInfo(
|
|
||||||
remoteId = "2",
|
|
||||||
name = "Porridge",
|
|
||||||
recipeYield = "3 servings",
|
|
||||||
recipeIngredients = listOf(SUGAR_INGREDIENT, MILK_INGREDIENT),
|
|
||||||
recipeInstructions = listOf(MIX_INSTRUCTION, BOIL_INSTRUCTION),
|
|
||||||
settings = RecipeSettingsInfo(disableAmounts = true)
|
|
||||||
)
|
|
||||||
|
|
||||||
val MIX_CAKE_RECIPE_INSTRUCTION_ENTITY = RecipeInstructionEntity(
|
|
||||||
recipeId = "1",
|
|
||||||
text = "Mix the ingredients",
|
|
||||||
)
|
|
||||||
|
|
||||||
private val BAKE_CAKE_RECIPE_INSTRUCTION_ENTITY = RecipeInstructionEntity(
|
|
||||||
recipeId = "1",
|
|
||||||
text = "Bake the ingredients",
|
|
||||||
)
|
|
||||||
|
|
||||||
val CAKE_RECIPE_ENTITY = RecipeEntity(
|
|
||||||
remoteId = "1",
|
|
||||||
recipeYield = "4 servings",
|
|
||||||
disableAmounts = true,
|
|
||||||
)
|
|
||||||
|
|
||||||
val CAKE_SUGAR_RECIPE_INGREDIENT_ENTITY = RecipeIngredientEntity(
|
|
||||||
recipeId = "1",
|
|
||||||
note = "2 oz of white sugar",
|
|
||||||
quantity = 1.0,
|
|
||||||
unit = null,
|
|
||||||
food = null,
|
|
||||||
title = null,
|
|
||||||
)
|
|
||||||
|
|
||||||
val CAKE_BREAD_RECIPE_INGREDIENT_ENTITY = RecipeIngredientEntity(
|
|
||||||
recipeId = "1",
|
|
||||||
note = "2 oz of white bread",
|
|
||||||
quantity = 1.0,
|
|
||||||
unit = null,
|
|
||||||
food = null,
|
|
||||||
title = null,
|
|
||||||
)
|
|
||||||
|
|
||||||
val FULL_CAKE_INFO_ENTITY = FullRecipeEntity(
|
|
||||||
recipeEntity = CAKE_RECIPE_ENTITY,
|
|
||||||
recipeSummaryEntity = CAKE_RECIPE_SUMMARY_ENTITY,
|
|
||||||
recipeIngredients = listOf(
|
|
||||||
CAKE_SUGAR_RECIPE_INGREDIENT_ENTITY,
|
|
||||||
CAKE_BREAD_RECIPE_INGREDIENT_ENTITY,
|
|
||||||
),
|
|
||||||
recipeInstructions = listOf(
|
|
||||||
MIX_CAKE_RECIPE_INSTRUCTION_ENTITY,
|
|
||||||
BAKE_CAKE_RECIPE_INSTRUCTION_ENTITY,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
private val PORRIDGE_RECIPE_ENTITY_FULL = RecipeEntity(
|
|
||||||
remoteId = "2",
|
|
||||||
recipeYield = "3 servings",
|
|
||||||
disableAmounts = true,
|
|
||||||
)
|
|
||||||
|
|
||||||
private val PORRIDGE_MILK_RECIPE_INGREDIENT_ENTITY = RecipeIngredientEntity(
|
|
||||||
recipeId = "2",
|
|
||||||
note = "2 oz of white milk",
|
|
||||||
quantity = 1.0,
|
|
||||||
unit = null,
|
|
||||||
food = null,
|
|
||||||
title = null,
|
|
||||||
)
|
|
||||||
|
|
||||||
private val PORRIDGE_SUGAR_RECIPE_INGREDIENT_ENTITY = RecipeIngredientEntity(
|
|
||||||
recipeId = "2",
|
|
||||||
note = "2 oz of white sugar",
|
|
||||||
quantity = 1.0,
|
|
||||||
unit = null,
|
|
||||||
food = null,
|
|
||||||
title = null,
|
|
||||||
)
|
|
||||||
|
|
||||||
private val PORRIDGE_MIX_RECIPE_INSTRUCTION_ENTITY = RecipeInstructionEntity(
|
|
||||||
recipeId = "2",
|
|
||||||
text = "Mix the ingredients"
|
|
||||||
)
|
|
||||||
|
|
||||||
private val PORRIDGE_BOIL_RECIPE_INSTRUCTION_ENTITY = RecipeInstructionEntity(
|
|
||||||
recipeId = "2",
|
|
||||||
text = "Boil the ingredients"
|
|
||||||
)
|
|
||||||
|
|
||||||
val FULL_PORRIDGE_INFO_ENTITY = FullRecipeEntity(
|
|
||||||
recipeEntity = PORRIDGE_RECIPE_ENTITY_FULL,
|
|
||||||
recipeSummaryEntity = PORRIDGE_RECIPE_SUMMARY_ENTITY,
|
|
||||||
recipeIngredients = listOf(
|
|
||||||
PORRIDGE_SUGAR_RECIPE_INGREDIENT_ENTITY,
|
|
||||||
PORRIDGE_MILK_RECIPE_INGREDIENT_ENTITY,
|
|
||||||
),
|
|
||||||
recipeInstructions = listOf(
|
|
||||||
PORRIDGE_MIX_RECIPE_INSTRUCTION_ENTITY,
|
|
||||||
PORRIDGE_BOIL_RECIPE_INSTRUCTION_ENTITY,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
val SUGAR_ADD_RECIPE_INGREDIENT_INFO = AddRecipeIngredientInfo("2 oz of white sugar")
|
|
||||||
|
|
||||||
val MILK_ADD_RECIPE_INGREDIENT_INFO = AddRecipeIngredientInfo("2 oz of white milk")
|
|
||||||
|
|
||||||
val BOIL_ADD_RECIPE_INSTRUCTION_INFO = AddRecipeInstructionInfo("Boil the ingredients")
|
|
||||||
|
|
||||||
val MIX_ADD_RECIPE_INSTRUCTION_INFO = AddRecipeInstructionInfo("Mix the ingredients")
|
|
||||||
|
|
||||||
val ADD_RECIPE_INFO_SETTINGS = AddRecipeSettingsInfo(disableComments = false, public = true)
|
|
||||||
|
|
||||||
val PORRIDGE_ADD_RECIPE_INFO = AddRecipeInfo(
|
|
||||||
name = "Porridge",
|
|
||||||
description = "A tasty porridge",
|
|
||||||
recipeYield = "3 servings",
|
|
||||||
recipeIngredient = listOf(
|
|
||||||
MILK_ADD_RECIPE_INGREDIENT_INFO,
|
|
||||||
SUGAR_ADD_RECIPE_INGREDIENT_INFO,
|
|
||||||
),
|
|
||||||
recipeInstructions = listOf(
|
|
||||||
MIX_ADD_RECIPE_INSTRUCTION_INFO,
|
|
||||||
BOIL_ADD_RECIPE_INSTRUCTION_INFO,
|
|
||||||
),
|
|
||||||
settings = ADD_RECIPE_INFO_SETTINGS,
|
|
||||||
)
|
|
||||||
|
|
||||||
val PORRIDGE_RECIPE_DRAFT = AddRecipeDraft(
|
|
||||||
recipeName = "Porridge",
|
|
||||||
recipeDescription = "A tasty porridge",
|
|
||||||
recipeYield = "3 servings",
|
|
||||||
recipeInstructions = listOf("Mix the ingredients", "Boil the ingredients"),
|
|
||||||
recipeIngredients = listOf("2 oz of white milk", "2 oz of white sugar"),
|
|
||||||
isRecipePublic = true,
|
|
||||||
areCommentsDisabled = false,
|
|
||||||
)
|
|
||||||
|
|
||||||
val PORRIDGE_RECIPE_SUMMARY_RESPONSE_V0 = GetRecipeSummaryResponseV0(
|
|
||||||
remoteId = 2,
|
|
||||||
name = "Porridge",
|
|
||||||
slug = "porridge",
|
|
||||||
description = "A tasty porridge",
|
|
||||||
dateAdded = LocalDate.parse("2021-11-12"),
|
|
||||||
dateUpdated = LocalDateTime.parse("2021-10-13T17:35:23"),
|
|
||||||
)
|
|
||||||
|
|
||||||
val PORRIDGE_RECIPE_SUMMARY_RESPONSE_V1 = GetRecipeSummaryResponseV1(
|
|
||||||
remoteId = "2",
|
|
||||||
name = "Porridge",
|
|
||||||
slug = "porridge",
|
|
||||||
description = "A tasty porridge",
|
|
||||||
dateAdded = LocalDate.parse("2021-11-12"),
|
|
||||||
dateUpdated = LocalDateTime.parse("2021-10-13T17:35:23"),
|
|
||||||
)
|
|
||||||
|
|
||||||
val VERSION_RESPONSE_V0 = VersionResponseV0("v0.5.6")
|
|
||||||
|
|
||||||
val VERSION_INFO_V0 = VersionInfo("v0.5.6")
|
|
||||||
|
|
||||||
val VERSION_RESPONSE_V1 = VersionResponseV1("v1.0.0-beta05")
|
|
||||||
|
|
||||||
val VERSION_INFO_V1 = VersionInfo("v1.0.0-beta05")
|
|
||||||
|
|
||||||
val MILK_RECIPE_INGREDIENT_RESPONSE_V0 = GetRecipeIngredientResponseV0("2 oz of white milk")
|
|
||||||
|
|
||||||
val SUGAR_RECIPE_INGREDIENT_RESPONSE_V0 = GetRecipeIngredientResponseV0("2 oz of white sugar")
|
|
||||||
|
|
||||||
val MILK_RECIPE_INGREDIENT_RESPONSE_V1 = GetRecipeIngredientResponseV1(
|
|
||||||
note = "2 oz of white milk",
|
|
||||||
quantity = 1.0,
|
|
||||||
unit = null,
|
|
||||||
food = null,
|
|
||||||
title = null,
|
|
||||||
)
|
|
||||||
|
|
||||||
val SUGAR_RECIPE_INGREDIENT_RESPONSE_V1 = GetRecipeIngredientResponseV1(
|
|
||||||
note = "2 oz of white sugar",
|
|
||||||
quantity = 1.0,
|
|
||||||
unit = null,
|
|
||||||
food = null,
|
|
||||||
title = null,
|
|
||||||
)
|
|
||||||
|
|
||||||
val MILK_RECIPE_INGREDIENT_INFO = RecipeIngredientInfo(
|
|
||||||
note = "2 oz of white milk",
|
|
||||||
quantity = 1.0,
|
|
||||||
unit = null,
|
|
||||||
food = null,
|
|
||||||
title = null,
|
|
||||||
)
|
|
||||||
|
|
||||||
val MIX_RECIPE_INSTRUCTION_RESPONSE_V0 = GetRecipeInstructionResponseV0("Mix the ingredients")
|
|
||||||
|
|
||||||
val BOIL_RECIPE_INSTRUCTION_RESPONSE_V0 = GetRecipeInstructionResponseV0("Boil the ingredients")
|
|
||||||
|
|
||||||
val MIX_RECIPE_INSTRUCTION_RESPONSE_V1 = GetRecipeInstructionResponseV1("Mix the ingredients")
|
|
||||||
|
|
||||||
val BOIL_RECIPE_INSTRUCTION_RESPONSE_V1 = GetRecipeInstructionResponseV1("Boil the ingredients")
|
|
||||||
|
|
||||||
val MIX_RECIPE_INSTRUCTION_INFO = RecipeInstructionInfo("Mix the ingredients")
|
|
||||||
|
|
||||||
val PORRIDGE_RECIPE_RESPONSE_V0 = GetRecipeResponseV0(
|
|
||||||
remoteId = 2,
|
|
||||||
name = "Porridge",
|
|
||||||
recipeYield = "3 servings",
|
|
||||||
recipeIngredients = listOf(
|
|
||||||
SUGAR_RECIPE_INGREDIENT_RESPONSE_V0,
|
|
||||||
MILK_RECIPE_INGREDIENT_RESPONSE_V0,
|
|
||||||
),
|
|
||||||
recipeInstructions = listOf(
|
|
||||||
MIX_RECIPE_INSTRUCTION_RESPONSE_V0,
|
|
||||||
BOIL_RECIPE_INSTRUCTION_RESPONSE_V0
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
val PORRIDGE_RECIPE_RESPONSE_V1 = GetRecipeResponseV1(
|
|
||||||
remoteId = "2",
|
|
||||||
name = "Porridge",
|
|
||||||
recipeYield = "3 servings",
|
|
||||||
recipeIngredients = listOf(
|
|
||||||
SUGAR_RECIPE_INGREDIENT_RESPONSE_V1,
|
|
||||||
MILK_RECIPE_INGREDIENT_RESPONSE_V1,
|
|
||||||
),
|
|
||||||
recipeInstructions = listOf(
|
|
||||||
MIX_RECIPE_INSTRUCTION_RESPONSE_V1,
|
|
||||||
BOIL_RECIPE_INSTRUCTION_RESPONSE_V1
|
|
||||||
),
|
|
||||||
settings = GetRecipeSettingsResponseV1(disableAmount = true),
|
|
||||||
)
|
|
||||||
|
|
||||||
val MIX_ADD_RECIPE_INSTRUCTION_REQUEST_V0 = AddRecipeInstructionV0("Mix the ingredients")
|
|
||||||
|
|
||||||
val BOIL_ADD_RECIPE_INSTRUCTION_REQUEST_V0 = AddRecipeInstructionV0("Boil the ingredients")
|
|
||||||
|
|
||||||
val SUGAR_ADD_RECIPE_INGREDIENT_REQUEST_V0 = AddRecipeIngredientV0("2 oz of white sugar")
|
|
||||||
|
|
||||||
val MILK_ADD_RECIPE_INGREDIENT_REQUEST_V0 = AddRecipeIngredientV0("2 oz of white milk")
|
|
||||||
|
|
||||||
val ADD_RECIPE_REQUEST_SETTINGS_V0 = AddRecipeSettingsV0(disableComments = false, public = true)
|
|
||||||
|
|
||||||
val PORRIDGE_ADD_RECIPE_REQUEST_V0 = AddRecipeRequestV0(
|
|
||||||
name = "Porridge",
|
|
||||||
description = "A tasty porridge",
|
|
||||||
recipeYield = "3 servings",
|
|
||||||
recipeInstructions = listOf(
|
|
||||||
MIX_ADD_RECIPE_INSTRUCTION_REQUEST_V0,
|
|
||||||
BOIL_ADD_RECIPE_INSTRUCTION_REQUEST_V0,
|
|
||||||
),
|
|
||||||
recipeIngredient = listOf(
|
|
||||||
MILK_ADD_RECIPE_INGREDIENT_REQUEST_V0,
|
|
||||||
SUGAR_ADD_RECIPE_INGREDIENT_REQUEST_V0,
|
|
||||||
),
|
|
||||||
settings = ADD_RECIPE_REQUEST_SETTINGS_V0
|
|
||||||
)
|
|
||||||
|
|
||||||
val MIX_ADD_RECIPE_INSTRUCTION_REQUEST_V1 = AddRecipeInstructionV1(
|
|
||||||
id = "1",
|
|
||||||
text = "Mix the ingredients",
|
|
||||||
ingredientReferences = emptyList()
|
|
||||||
)
|
|
||||||
|
|
||||||
val BOIL_ADD_RECIPE_INSTRUCTION_REQUEST_V1 = AddRecipeInstructionV1(
|
|
||||||
id = "2",
|
|
||||||
text = "Boil the ingredients",
|
|
||||||
ingredientReferences = emptyList()
|
|
||||||
)
|
|
||||||
|
|
||||||
val SUGAR_ADD_RECIPE_INGREDIENT_REQUEST_V1 = AddRecipeIngredientV1(
|
|
||||||
id = "3",
|
|
||||||
note = "2 oz of white sugar"
|
|
||||||
)
|
|
||||||
|
|
||||||
val MILK_ADD_RECIPE_INGREDIENT_REQUEST_V1 = AddRecipeIngredientV1(
|
|
||||||
id = "4",
|
|
||||||
note = "2 oz of white milk"
|
|
||||||
)
|
|
||||||
|
|
||||||
val ADD_RECIPE_REQUEST_SETTINGS_V1 = AddRecipeSettingsV1(disableComments = false, public = true)
|
|
||||||
|
|
||||||
val PORRIDGE_CREATE_RECIPE_REQUEST_V1 = CreateRecipeRequestV1(name = "Porridge")
|
|
||||||
|
|
||||||
val PORRIDGE_UPDATE_RECIPE_REQUEST_V1 = UpdateRecipeRequestV1(
|
|
||||||
description = "A tasty porridge",
|
|
||||||
recipeYield = "3 servings",
|
|
||||||
recipeInstructions = listOf(
|
|
||||||
MIX_ADD_RECIPE_INSTRUCTION_REQUEST_V1,
|
|
||||||
BOIL_ADD_RECIPE_INSTRUCTION_REQUEST_V1,
|
|
||||||
),
|
|
||||||
recipeIngredient = listOf(
|
|
||||||
MILK_ADD_RECIPE_INGREDIENT_REQUEST_V1,
|
|
||||||
SUGAR_ADD_RECIPE_INGREDIENT_REQUEST_V1,
|
|
||||||
),
|
|
||||||
settings = ADD_RECIPE_REQUEST_SETTINGS_V1
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -6,10 +6,13 @@ import gq.kirmanak.mealient.data.disclaimer.DisclaimerStorage
|
|||||||
import gq.kirmanak.mealient.data.recipes.RecipeRepo
|
import gq.kirmanak.mealient.data.recipes.RecipeRepo
|
||||||
import gq.kirmanak.mealient.test.AuthImplTestData.TEST_BASE_URL
|
import gq.kirmanak.mealient.test.AuthImplTestData.TEST_BASE_URL
|
||||||
import gq.kirmanak.mealient.test.BaseUnitTest
|
import gq.kirmanak.mealient.test.BaseUnitTest
|
||||||
|
import gq.kirmanak.mealient.ui.ActivityUiState
|
||||||
|
import gq.kirmanak.mealient.ui.ActivityUiStateController
|
||||||
import io.mockk.coEvery
|
import io.mockk.coEvery
|
||||||
import io.mockk.every
|
import io.mockk.every
|
||||||
import io.mockk.impl.annotations.MockK
|
import io.mockk.impl.annotations.MockK
|
||||||
import io.mockk.verify
|
import io.mockk.verify
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.emptyFlow
|
import kotlinx.coroutines.flow.emptyFlow
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
@@ -28,6 +31,9 @@ class MainActivityViewModelTest : BaseUnitTest() {
|
|||||||
@MockK(relaxUnitFun = true)
|
@MockK(relaxUnitFun = true)
|
||||||
lateinit var recipeRepo: RecipeRepo
|
lateinit var recipeRepo: RecipeRepo
|
||||||
|
|
||||||
|
@MockK(relaxUnitFun = true)
|
||||||
|
lateinit var activityUiStateController: ActivityUiStateController
|
||||||
|
|
||||||
private lateinit var subject: MainActivityViewModel
|
private lateinit var subject: MainActivityViewModel
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
@@ -36,12 +42,17 @@ class MainActivityViewModelTest : BaseUnitTest() {
|
|||||||
every { authRepo.isAuthorizedFlow } returns emptyFlow()
|
every { authRepo.isAuthorizedFlow } returns emptyFlow()
|
||||||
coEvery { disclaimerStorage.isDisclaimerAccepted() } returns true
|
coEvery { disclaimerStorage.isDisclaimerAccepted() } returns true
|
||||||
coEvery { serverInfoRepo.getUrl() } returns TEST_BASE_URL
|
coEvery { serverInfoRepo.getUrl() } returns TEST_BASE_URL
|
||||||
|
every { activityUiStateController.getUiStateFlow() } returns MutableStateFlow(
|
||||||
|
ActivityUiState()
|
||||||
|
)
|
||||||
|
coEvery { serverInfoRepo.versionUpdates() } returns emptyFlow()
|
||||||
subject = MainActivityViewModel(
|
subject = MainActivityViewModel(
|
||||||
authRepo = authRepo,
|
authRepo = authRepo,
|
||||||
logger = logger,
|
logger = logger,
|
||||||
disclaimerStorage = disclaimerStorage,
|
disclaimerStorage = disclaimerStorage,
|
||||||
serverInfoRepo = serverInfoRepo,
|
serverInfoRepo = serverInfoRepo,
|
||||||
recipeRepo = recipeRepo,
|
recipeRepo = recipeRepo,
|
||||||
|
activityUiStateController = activityUiStateController,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ package gq.kirmanak.mealient.ui.add
|
|||||||
|
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import gq.kirmanak.mealient.data.add.AddRecipeRepo
|
import gq.kirmanak.mealient.data.add.AddRecipeRepo
|
||||||
|
import gq.kirmanak.mealient.datasource_test.PORRIDGE_ADD_RECIPE_INFO
|
||||||
import gq.kirmanak.mealient.test.BaseUnitTest
|
import gq.kirmanak.mealient.test.BaseUnitTest
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.PORRIDGE_ADD_RECIPE_INFO
|
|
||||||
import io.mockk.coEvery
|
import io.mockk.coEvery
|
||||||
import io.mockk.coVerify
|
import io.mockk.coVerify
|
||||||
import io.mockk.impl.annotations.MockK
|
import io.mockk.impl.annotations.MockK
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import gq.kirmanak.mealient.data.auth.AuthRepo
|
|||||||
import gq.kirmanak.mealient.data.baseurl.ServerInfoRepo
|
import gq.kirmanak.mealient.data.baseurl.ServerInfoRepo
|
||||||
import gq.kirmanak.mealient.data.recipes.RecipeRepo
|
import gq.kirmanak.mealient.data.recipes.RecipeRepo
|
||||||
import gq.kirmanak.mealient.datasource.NetworkError
|
import gq.kirmanak.mealient.datasource.NetworkError
|
||||||
|
import gq.kirmanak.mealient.shopping_lists.repo.ShoppingListsRepo
|
||||||
import gq.kirmanak.mealient.test.AuthImplTestData.TEST_BASE_URL
|
import gq.kirmanak.mealient.test.AuthImplTestData.TEST_BASE_URL
|
||||||
import gq.kirmanak.mealient.test.BaseUnitTest
|
import gq.kirmanak.mealient.test.BaseUnitTest
|
||||||
import gq.kirmanak.mealient.ui.OperationUiState
|
import gq.kirmanak.mealient.ui.OperationUiState
|
||||||
@@ -31,6 +32,9 @@ class BaseURLViewModelTest : BaseUnitTest() {
|
|||||||
@MockK(relaxUnitFun = true)
|
@MockK(relaxUnitFun = true)
|
||||||
lateinit var recipeRepo: RecipeRepo
|
lateinit var recipeRepo: RecipeRepo
|
||||||
|
|
||||||
|
@MockK(relaxUnitFun = true)
|
||||||
|
lateinit var shoppingListsRepo: ShoppingListsRepo
|
||||||
|
|
||||||
lateinit var subject: BaseURLViewModel
|
lateinit var subject: BaseURLViewModel
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
@@ -41,6 +45,7 @@ class BaseURLViewModelTest : BaseUnitTest() {
|
|||||||
authRepo = authRepo,
|
authRepo = authRepo,
|
||||||
recipeRepo = recipeRepo,
|
recipeRepo = recipeRepo,
|
||||||
logger = logger,
|
logger = logger,
|
||||||
|
shoppingListsRepo = shoppingListsRepo,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import androidx.lifecycle.asFlow
|
|||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import gq.kirmanak.mealient.data.auth.AuthRepo
|
import gq.kirmanak.mealient.data.auth.AuthRepo
|
||||||
import gq.kirmanak.mealient.data.recipes.RecipeRepo
|
import gq.kirmanak.mealient.data.recipes.RecipeRepo
|
||||||
|
import gq.kirmanak.mealient.database.CAKE_RECIPE_SUMMARY_ENTITY
|
||||||
import gq.kirmanak.mealient.test.BaseUnitTest
|
import gq.kirmanak.mealient.test.BaseUnitTest
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.CAKE_RECIPE_SUMMARY_ENTITY
|
|
||||||
import io.mockk.coEvery
|
import io.mockk.coEvery
|
||||||
import io.mockk.coVerify
|
import io.mockk.coVerify
|
||||||
import io.mockk.every
|
import io.mockk.every
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package gq.kirmanak.mealient.ui.recipes.info
|
|||||||
import androidx.lifecycle.asFlow
|
import androidx.lifecycle.asFlow
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import gq.kirmanak.mealient.data.recipes.RecipeRepo
|
import gq.kirmanak.mealient.data.recipes.RecipeRepo
|
||||||
|
import gq.kirmanak.mealient.database.FULL_CAKE_INFO_ENTITY
|
||||||
import gq.kirmanak.mealient.test.BaseUnitTest
|
import gq.kirmanak.mealient.test.BaseUnitTest
|
||||||
import gq.kirmanak.mealient.test.RecipeImplTestData.FULL_CAKE_INFO_ENTITY
|
|
||||||
import io.mockk.coEvery
|
import io.mockk.coEvery
|
||||||
import io.mockk.impl.annotations.MockK
|
import io.mockk.impl.annotations.MockK
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
|||||||
@@ -11,4 +11,10 @@ android {
|
|||||||
dependencies {
|
dependencies {
|
||||||
implementation(libs.google.dagger.hiltAndroid)
|
implementation(libs.google.dagger.hiltAndroid)
|
||||||
kapt(libs.google.dagger.hiltCompiler)
|
kapt(libs.google.dagger.hiltCompiler)
|
||||||
|
|
||||||
|
testImplementation(libs.jetbrains.kotlinx.coroutinesTest)
|
||||||
|
testImplementation(libs.androidx.test.junit)
|
||||||
|
testImplementation(libs.androidx.coreTesting)
|
||||||
|
testImplementation(libs.google.truth)
|
||||||
|
testImplementation(project(":testing"))
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package gq.kirmanak.mealient.extensions
|
package gq.kirmanak.mealient.architecture
|
||||||
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.FlowCollector
|
import kotlinx.coroutines.flow.FlowCollector
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package gq.kirmanak.mealient.extensions
|
package gq.kirmanak.mealient.architecture
|
||||||
|
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import gq.kirmanak.mealient.test.BaseUnitTest
|
import gq.kirmanak.mealient.test.BaseUnitTest
|
||||||
@@ -19,5 +19,9 @@ gradlePlugin {
|
|||||||
id = "gq.kirmanak.mealient.library"
|
id = "gq.kirmanak.mealient.library"
|
||||||
implementationClass = "AndroidLibraryConventionPlugin"
|
implementationClass = "AndroidLibraryConventionPlugin"
|
||||||
}
|
}
|
||||||
|
register("compose") {
|
||||||
|
id = "gq.kirmanak.mealient.compose"
|
||||||
|
implementationClass = "AndroidLibraryComposeConventionPlugin"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import com.android.build.gradle.LibraryExtension
|
||||||
|
import gq.kirmanak.mealient.configureAndroidCompose
|
||||||
|
import org.gradle.api.Plugin
|
||||||
|
import org.gradle.api.Project
|
||||||
|
import org.gradle.kotlin.dsl.configure
|
||||||
|
|
||||||
|
class AndroidLibraryComposeConventionPlugin : Plugin<Project> {
|
||||||
|
|
||||||
|
override fun apply(target: Project) {
|
||||||
|
with(target) {
|
||||||
|
extensions.configure<LibraryExtension> {
|
||||||
|
configureAndroidCompose(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
package gq.kirmanak.mealient
|
||||||
|
|
||||||
|
import com.android.build.api.dsl.CommonExtension
|
||||||
|
import com.android.build.gradle.LibraryExtension
|
||||||
|
import com.android.build.gradle.internal.dsl.BaseAppModuleExtension
|
||||||
|
import org.gradle.api.Action
|
||||||
|
import org.gradle.api.NamedDomainObjectContainer
|
||||||
|
import org.gradle.api.Project
|
||||||
|
import org.gradle.api.artifacts.MinimalExternalModuleDependency
|
||||||
|
import org.gradle.api.plugins.ExtensionAware
|
||||||
|
import org.gradle.api.provider.Provider
|
||||||
|
import org.gradle.kotlin.dsl.dependencies
|
||||||
|
import org.jetbrains.kotlin.gradle.dsl.KotlinAndroidProjectExtension
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||||
|
|
||||||
|
internal fun Project.configureAndroidCompose(
|
||||||
|
commonExtension: CommonExtension<*, *, *, *>,
|
||||||
|
) {
|
||||||
|
val variants = when (commonExtension) {
|
||||||
|
is BaseAppModuleExtension -> commonExtension.applicationVariants
|
||||||
|
is LibraryExtension -> commonExtension.libraryVariants
|
||||||
|
else -> error("Unsupported extension type")
|
||||||
|
}
|
||||||
|
|
||||||
|
commonExtension.apply {
|
||||||
|
buildFeatures {
|
||||||
|
compose = true
|
||||||
|
}
|
||||||
|
|
||||||
|
composeOptions {
|
||||||
|
val version = libs.findVersion("composeKotlinCompilerExtension")
|
||||||
|
kotlinCompilerExtensionVersion = version.get().toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add compose-destinations generated code to Gradle source sets
|
||||||
|
variants.all {
|
||||||
|
kotlin.sourceSets {
|
||||||
|
getByName(name) {
|
||||||
|
kotlin.srcDir("build/generated/ksp/$name/kotlin")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
val bom = library("androidx-compose-bom")
|
||||||
|
add("implementation", platform(bom))
|
||||||
|
add("androidTestImplementation", platform(bom))
|
||||||
|
|
||||||
|
add("implementation", library("androidx-compose-material3"))
|
||||||
|
add("implementation", library("androidx-compose-ui-toolingPreview"))
|
||||||
|
add("implementation", library("androidx-compose-runtime-livedata"))
|
||||||
|
add("implementation", library("androidx-lifecycle-viewmodelCompose"))
|
||||||
|
add("implementation", library("google-accompanist-themeadapter-material3"))
|
||||||
|
add("debugImplementation", library("androidx-compose-ui-tooling"))
|
||||||
|
add("debugImplementation", library("androidx-compose-ui-testManifest"))
|
||||||
|
add("androidTestImplementation", library("androidx-compose-ui-testJunit"))
|
||||||
|
add("implementation", library("composeDestinations-core"))
|
||||||
|
add("ksp", library("composeDestinations-ksp"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Project.library(name: String): Provider<MinimalExternalModuleDependency> {
|
||||||
|
return libs.findLibrary(name).get()
|
||||||
|
}
|
||||||
|
|
||||||
|
private val Project.kotlin: KotlinAndroidProjectExtension
|
||||||
|
get() = (this as ExtensionAware).extensions.getByName("kotlin") as KotlinAndroidProjectExtension
|
||||||
|
|
||||||
|
private fun KotlinAndroidProjectExtension.sourceSets(configure: Action<NamedDomainObjectContainer<KotlinSourceSet>>): Unit =
|
||||||
|
(this as ExtensionAware).extensions.configure("sourceSets", configure)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -27,7 +27,11 @@ internal fun Project.configureKotlinAndroid(
|
|||||||
}
|
}
|
||||||
|
|
||||||
lint {
|
lint {
|
||||||
disable += listOf("ObsoleteLintCustomCheck", "IconMissingDensityFolder")
|
disable += listOf(
|
||||||
|
"ObsoleteLintCustomCheck",
|
||||||
|
"IconMissingDensityFolder",
|
||||||
|
"MissingTranslation"
|
||||||
|
)
|
||||||
enable += listOf(
|
enable += listOf(
|
||||||
"ConvertToWebp",
|
"ConvertToWebp",
|
||||||
"DuplicateStrings",
|
"DuplicateStrings",
|
||||||
|
|||||||
@@ -6,30 +6,27 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
defaultConfig {
|
|
||||||
ksp {
|
|
||||||
arg("room.schemaLocation", "$projectDir/schemas")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace = "gq.kirmanak.mealient.database"
|
namespace = "gq.kirmanak.mealient.database"
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
implementation(project(":logging"))
|
||||||
|
testImplementation(project(":testing"))
|
||||||
|
testImplementation(project(":database_test"))
|
||||||
|
|
||||||
implementation(libs.google.dagger.hiltAndroid)
|
implementation(libs.google.dagger.hiltAndroid)
|
||||||
kapt(libs.google.dagger.hiltCompiler)
|
kapt(libs.google.dagger.hiltCompiler)
|
||||||
kaptTest(libs.google.dagger.hiltAndroidCompiler)
|
kaptTest(libs.google.dagger.hiltAndroidCompiler)
|
||||||
testImplementation(libs.google.dagger.hiltAndroidTesting)
|
testImplementation(libs.google.dagger.hiltAndroidTesting)
|
||||||
|
|
||||||
// withTransaction is used in the app module
|
implementation(libs.androidx.room.ktx)
|
||||||
api(libs.androidx.room.ktx)
|
|
||||||
|
|
||||||
implementation(libs.androidx.room.runtime)
|
implementation(libs.androidx.room.runtime)
|
||||||
implementation(libs.androidx.room.paging)
|
implementation(libs.androidx.room.paging)
|
||||||
ksp(libs.androidx.room.compiler)
|
ksp(libs.androidx.room.compiler)
|
||||||
testImplementation(libs.androidx.room.testing)
|
testImplementation(libs.androidx.room.testing)
|
||||||
|
|
||||||
implementation(libs.jetbrains.kotlinx.datetime)
|
api(libs.jetbrains.kotlinx.datetime)
|
||||||
|
|
||||||
implementation(libs.jetbrains.kotlinx.coroutinesAndroid)
|
implementation(libs.jetbrains.kotlinx.coroutinesAndroid)
|
||||||
testImplementation(libs.jetbrains.kotlinx.coroutinesTest)
|
testImplementation(libs.jetbrains.kotlinx.coroutinesTest)
|
||||||
|
|||||||
@@ -1,404 +0,0 @@
|
|||||||
{
|
|
||||||
"formatVersion": 1,
|
|
||||||
"database": {
|
|
||||||
"version": 1,
|
|
||||||
"identityHash": "cac9e9a2f4082b071336eff342e0c01f",
|
|
||||||
"entities": [
|
|
||||||
{
|
|
||||||
"tableName": "categories",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`local_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL)",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "localId",
|
|
||||||
"columnName": "local_id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "name",
|
|
||||||
"columnName": "name",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"local_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": true
|
|
||||||
},
|
|
||||||
"indices": [
|
|
||||||
{
|
|
||||||
"name": "index_categories_name",
|
|
||||||
"unique": true,
|
|
||||||
"columnNames": [
|
|
||||||
"name"
|
|
||||||
],
|
|
||||||
"orders": [],
|
|
||||||
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_categories_name` ON `${TABLE_NAME}` (`name`)"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"foreignKeys": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "category_recipe",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`category_id` INTEGER NOT NULL, `recipe_id` INTEGER NOT NULL, PRIMARY KEY(`category_id`, `recipe_id`), FOREIGN KEY(`category_id`) REFERENCES `categories`(`local_id`) ON UPDATE CASCADE ON DELETE CASCADE , FOREIGN KEY(`recipe_id`) REFERENCES `recipe_summaries`(`remote_id`) ON UPDATE CASCADE ON DELETE CASCADE )",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "categoryId",
|
|
||||||
"columnName": "category_id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "recipeId",
|
|
||||||
"columnName": "recipe_id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"category_id",
|
|
||||||
"recipe_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": false
|
|
||||||
},
|
|
||||||
"indices": [
|
|
||||||
{
|
|
||||||
"name": "index_category_recipe_category_id_recipe_id",
|
|
||||||
"unique": true,
|
|
||||||
"columnNames": [
|
|
||||||
"category_id",
|
|
||||||
"recipe_id"
|
|
||||||
],
|
|
||||||
"orders": [],
|
|
||||||
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_category_recipe_category_id_recipe_id` ON `${TABLE_NAME}` (`category_id`, `recipe_id`)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "index_category_recipe_recipe_id",
|
|
||||||
"unique": false,
|
|
||||||
"columnNames": [
|
|
||||||
"recipe_id"
|
|
||||||
],
|
|
||||||
"orders": [],
|
|
||||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_category_recipe_recipe_id` ON `${TABLE_NAME}` (`recipe_id`)"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"foreignKeys": [
|
|
||||||
{
|
|
||||||
"table": "categories",
|
|
||||||
"onDelete": "CASCADE",
|
|
||||||
"onUpdate": "CASCADE",
|
|
||||||
"columns": [
|
|
||||||
"category_id"
|
|
||||||
],
|
|
||||||
"referencedColumns": [
|
|
||||||
"local_id"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"table": "recipe_summaries",
|
|
||||||
"onDelete": "CASCADE",
|
|
||||||
"onUpdate": "CASCADE",
|
|
||||||
"columns": [
|
|
||||||
"recipe_id"
|
|
||||||
],
|
|
||||||
"referencedColumns": [
|
|
||||||
"remote_id"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "tags",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`local_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL)",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "localId",
|
|
||||||
"columnName": "local_id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "name",
|
|
||||||
"columnName": "name",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"local_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": true
|
|
||||||
},
|
|
||||||
"indices": [
|
|
||||||
{
|
|
||||||
"name": "index_tags_name",
|
|
||||||
"unique": true,
|
|
||||||
"columnNames": [
|
|
||||||
"name"
|
|
||||||
],
|
|
||||||
"orders": [],
|
|
||||||
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_tags_name` ON `${TABLE_NAME}` (`name`)"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"foreignKeys": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "tag_recipe",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`tag_id` INTEGER NOT NULL, `recipe_id` INTEGER NOT NULL, PRIMARY KEY(`tag_id`, `recipe_id`), FOREIGN KEY(`tag_id`) REFERENCES `tags`(`local_id`) ON UPDATE CASCADE ON DELETE CASCADE , FOREIGN KEY(`recipe_id`) REFERENCES `recipe_summaries`(`remote_id`) ON UPDATE CASCADE ON DELETE CASCADE )",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "tagId",
|
|
||||||
"columnName": "tag_id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "recipeId",
|
|
||||||
"columnName": "recipe_id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"tag_id",
|
|
||||||
"recipe_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": false
|
|
||||||
},
|
|
||||||
"indices": [
|
|
||||||
{
|
|
||||||
"name": "index_tag_recipe_recipe_id",
|
|
||||||
"unique": false,
|
|
||||||
"columnNames": [
|
|
||||||
"recipe_id"
|
|
||||||
],
|
|
||||||
"orders": [],
|
|
||||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_tag_recipe_recipe_id` ON `${TABLE_NAME}` (`recipe_id`)"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"foreignKeys": [
|
|
||||||
{
|
|
||||||
"table": "tags",
|
|
||||||
"onDelete": "CASCADE",
|
|
||||||
"onUpdate": "CASCADE",
|
|
||||||
"columns": [
|
|
||||||
"tag_id"
|
|
||||||
],
|
|
||||||
"referencedColumns": [
|
|
||||||
"local_id"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"table": "recipe_summaries",
|
|
||||||
"onDelete": "CASCADE",
|
|
||||||
"onUpdate": "CASCADE",
|
|
||||||
"columns": [
|
|
||||||
"recipe_id"
|
|
||||||
],
|
|
||||||
"referencedColumns": [
|
|
||||||
"remote_id"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "recipe_summaries",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`remote_id` INTEGER NOT NULL, `name` TEXT NOT NULL, `slug` TEXT NOT NULL, `image` TEXT, `description` TEXT NOT NULL, `rating` INTEGER, `date_added` INTEGER NOT NULL, `date_updated` INTEGER NOT NULL, PRIMARY KEY(`remote_id`))",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "remoteId",
|
|
||||||
"columnName": "remote_id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "name",
|
|
||||||
"columnName": "name",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "slug",
|
|
||||||
"columnName": "slug",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "image",
|
|
||||||
"columnName": "image",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "description",
|
|
||||||
"columnName": "description",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "rating",
|
|
||||||
"columnName": "rating",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "dateAdded",
|
|
||||||
"columnName": "date_added",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "dateUpdated",
|
|
||||||
"columnName": "date_updated",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"remote_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": false
|
|
||||||
},
|
|
||||||
"indices": [],
|
|
||||||
"foreignKeys": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "recipe",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`remote_id` INTEGER NOT NULL, `recipe_yield` TEXT NOT NULL, PRIMARY KEY(`remote_id`))",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "remoteId",
|
|
||||||
"columnName": "remote_id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "recipeYield",
|
|
||||||
"columnName": "recipe_yield",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"remote_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": false
|
|
||||||
},
|
|
||||||
"indices": [],
|
|
||||||
"foreignKeys": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "recipe_ingredient",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`local_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `recipe_id` INTEGER NOT NULL, `title` TEXT NOT NULL, `note` TEXT NOT NULL, `unit` TEXT NOT NULL, `food` TEXT NOT NULL, `disable_amount` INTEGER NOT NULL, `quantity` INTEGER NOT NULL)",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "localId",
|
|
||||||
"columnName": "local_id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "recipeId",
|
|
||||||
"columnName": "recipe_id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "title",
|
|
||||||
"columnName": "title",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "note",
|
|
||||||
"columnName": "note",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "unit",
|
|
||||||
"columnName": "unit",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "food",
|
|
||||||
"columnName": "food",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "disableAmount",
|
|
||||||
"columnName": "disable_amount",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "quantity",
|
|
||||||
"columnName": "quantity",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"local_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": true
|
|
||||||
},
|
|
||||||
"indices": [],
|
|
||||||
"foreignKeys": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "recipe_instruction",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`local_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `recipe_id` INTEGER NOT NULL, `title` TEXT NOT NULL, `text` TEXT NOT NULL)",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "localId",
|
|
||||||
"columnName": "local_id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "recipeId",
|
|
||||||
"columnName": "recipe_id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "title",
|
|
||||||
"columnName": "title",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "text",
|
|
||||||
"columnName": "text",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"local_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": true
|
|
||||||
},
|
|
||||||
"indices": [],
|
|
||||||
"foreignKeys": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"views": [],
|
|
||||||
"setupQueries": [
|
|
||||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
|
||||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'cac9e9a2f4082b071336eff342e0c01f')"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,404 +0,0 @@
|
|||||||
{
|
|
||||||
"formatVersion": 1,
|
|
||||||
"database": {
|
|
||||||
"version": 2,
|
|
||||||
"identityHash": "cac9e9a2f4082b071336eff342e0c01f",
|
|
||||||
"entities": [
|
|
||||||
{
|
|
||||||
"tableName": "categories",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`local_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL)",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "localId",
|
|
||||||
"columnName": "local_id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "name",
|
|
||||||
"columnName": "name",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"local_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": true
|
|
||||||
},
|
|
||||||
"indices": [
|
|
||||||
{
|
|
||||||
"name": "index_categories_name",
|
|
||||||
"unique": true,
|
|
||||||
"columnNames": [
|
|
||||||
"name"
|
|
||||||
],
|
|
||||||
"orders": [],
|
|
||||||
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_categories_name` ON `${TABLE_NAME}` (`name`)"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"foreignKeys": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "category_recipe",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`category_id` INTEGER NOT NULL, `recipe_id` INTEGER NOT NULL, PRIMARY KEY(`category_id`, `recipe_id`), FOREIGN KEY(`category_id`) REFERENCES `categories`(`local_id`) ON UPDATE CASCADE ON DELETE CASCADE , FOREIGN KEY(`recipe_id`) REFERENCES `recipe_summaries`(`remote_id`) ON UPDATE CASCADE ON DELETE CASCADE )",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "categoryId",
|
|
||||||
"columnName": "category_id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "recipeId",
|
|
||||||
"columnName": "recipe_id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"category_id",
|
|
||||||
"recipe_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": false
|
|
||||||
},
|
|
||||||
"indices": [
|
|
||||||
{
|
|
||||||
"name": "index_category_recipe_category_id_recipe_id",
|
|
||||||
"unique": true,
|
|
||||||
"columnNames": [
|
|
||||||
"category_id",
|
|
||||||
"recipe_id"
|
|
||||||
],
|
|
||||||
"orders": [],
|
|
||||||
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_category_recipe_category_id_recipe_id` ON `${TABLE_NAME}` (`category_id`, `recipe_id`)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "index_category_recipe_recipe_id",
|
|
||||||
"unique": false,
|
|
||||||
"columnNames": [
|
|
||||||
"recipe_id"
|
|
||||||
],
|
|
||||||
"orders": [],
|
|
||||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_category_recipe_recipe_id` ON `${TABLE_NAME}` (`recipe_id`)"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"foreignKeys": [
|
|
||||||
{
|
|
||||||
"table": "categories",
|
|
||||||
"onDelete": "CASCADE",
|
|
||||||
"onUpdate": "CASCADE",
|
|
||||||
"columns": [
|
|
||||||
"category_id"
|
|
||||||
],
|
|
||||||
"referencedColumns": [
|
|
||||||
"local_id"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"table": "recipe_summaries",
|
|
||||||
"onDelete": "CASCADE",
|
|
||||||
"onUpdate": "CASCADE",
|
|
||||||
"columns": [
|
|
||||||
"recipe_id"
|
|
||||||
],
|
|
||||||
"referencedColumns": [
|
|
||||||
"remote_id"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "tags",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`local_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL)",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "localId",
|
|
||||||
"columnName": "local_id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "name",
|
|
||||||
"columnName": "name",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"local_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": true
|
|
||||||
},
|
|
||||||
"indices": [
|
|
||||||
{
|
|
||||||
"name": "index_tags_name",
|
|
||||||
"unique": true,
|
|
||||||
"columnNames": [
|
|
||||||
"name"
|
|
||||||
],
|
|
||||||
"orders": [],
|
|
||||||
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_tags_name` ON `${TABLE_NAME}` (`name`)"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"foreignKeys": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "tag_recipe",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`tag_id` INTEGER NOT NULL, `recipe_id` INTEGER NOT NULL, PRIMARY KEY(`tag_id`, `recipe_id`), FOREIGN KEY(`tag_id`) REFERENCES `tags`(`local_id`) ON UPDATE CASCADE ON DELETE CASCADE , FOREIGN KEY(`recipe_id`) REFERENCES `recipe_summaries`(`remote_id`) ON UPDATE CASCADE ON DELETE CASCADE )",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "tagId",
|
|
||||||
"columnName": "tag_id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "recipeId",
|
|
||||||
"columnName": "recipe_id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"tag_id",
|
|
||||||
"recipe_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": false
|
|
||||||
},
|
|
||||||
"indices": [
|
|
||||||
{
|
|
||||||
"name": "index_tag_recipe_recipe_id",
|
|
||||||
"unique": false,
|
|
||||||
"columnNames": [
|
|
||||||
"recipe_id"
|
|
||||||
],
|
|
||||||
"orders": [],
|
|
||||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_tag_recipe_recipe_id` ON `${TABLE_NAME}` (`recipe_id`)"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"foreignKeys": [
|
|
||||||
{
|
|
||||||
"table": "tags",
|
|
||||||
"onDelete": "CASCADE",
|
|
||||||
"onUpdate": "CASCADE",
|
|
||||||
"columns": [
|
|
||||||
"tag_id"
|
|
||||||
],
|
|
||||||
"referencedColumns": [
|
|
||||||
"local_id"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"table": "recipe_summaries",
|
|
||||||
"onDelete": "CASCADE",
|
|
||||||
"onUpdate": "CASCADE",
|
|
||||||
"columns": [
|
|
||||||
"recipe_id"
|
|
||||||
],
|
|
||||||
"referencedColumns": [
|
|
||||||
"remote_id"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "recipe_summaries",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`remote_id` INTEGER NOT NULL, `name` TEXT NOT NULL, `slug` TEXT NOT NULL, `image` TEXT, `description` TEXT NOT NULL, `rating` INTEGER, `date_added` INTEGER NOT NULL, `date_updated` INTEGER NOT NULL, PRIMARY KEY(`remote_id`))",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "remoteId",
|
|
||||||
"columnName": "remote_id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "name",
|
|
||||||
"columnName": "name",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "slug",
|
|
||||||
"columnName": "slug",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "image",
|
|
||||||
"columnName": "image",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "description",
|
|
||||||
"columnName": "description",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "rating",
|
|
||||||
"columnName": "rating",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "dateAdded",
|
|
||||||
"columnName": "date_added",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "dateUpdated",
|
|
||||||
"columnName": "date_updated",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"remote_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": false
|
|
||||||
},
|
|
||||||
"indices": [],
|
|
||||||
"foreignKeys": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "recipe",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`remote_id` INTEGER NOT NULL, `recipe_yield` TEXT NOT NULL, PRIMARY KEY(`remote_id`))",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "remoteId",
|
|
||||||
"columnName": "remote_id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "recipeYield",
|
|
||||||
"columnName": "recipe_yield",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"remote_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": false
|
|
||||||
},
|
|
||||||
"indices": [],
|
|
||||||
"foreignKeys": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "recipe_ingredient",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`local_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `recipe_id` INTEGER NOT NULL, `title` TEXT NOT NULL, `note` TEXT NOT NULL, `unit` TEXT NOT NULL, `food` TEXT NOT NULL, `disable_amount` INTEGER NOT NULL, `quantity` INTEGER NOT NULL)",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "localId",
|
|
||||||
"columnName": "local_id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "recipeId",
|
|
||||||
"columnName": "recipe_id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "title",
|
|
||||||
"columnName": "title",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "note",
|
|
||||||
"columnName": "note",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "unit",
|
|
||||||
"columnName": "unit",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "food",
|
|
||||||
"columnName": "food",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "disableAmount",
|
|
||||||
"columnName": "disable_amount",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "quantity",
|
|
||||||
"columnName": "quantity",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"local_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": true
|
|
||||||
},
|
|
||||||
"indices": [],
|
|
||||||
"foreignKeys": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "recipe_instruction",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`local_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `recipe_id` INTEGER NOT NULL, `title` TEXT NOT NULL, `text` TEXT NOT NULL)",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "localId",
|
|
||||||
"columnName": "local_id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "recipeId",
|
|
||||||
"columnName": "recipe_id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "title",
|
|
||||||
"columnName": "title",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "text",
|
|
||||||
"columnName": "text",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"local_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": true
|
|
||||||
},
|
|
||||||
"indices": [],
|
|
||||||
"foreignKeys": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"views": [],
|
|
||||||
"setupQueries": [
|
|
||||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
|
||||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'cac9e9a2f4082b071336eff342e0c01f')"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,404 +0,0 @@
|
|||||||
{
|
|
||||||
"formatVersion": 1,
|
|
||||||
"database": {
|
|
||||||
"version": 3,
|
|
||||||
"identityHash": "28c896eb34e95c0cff33148178252f72",
|
|
||||||
"entities": [
|
|
||||||
{
|
|
||||||
"tableName": "categories",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`local_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL)",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "localId",
|
|
||||||
"columnName": "local_id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "name",
|
|
||||||
"columnName": "name",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"local_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": true
|
|
||||||
},
|
|
||||||
"indices": [
|
|
||||||
{
|
|
||||||
"name": "index_categories_name",
|
|
||||||
"unique": true,
|
|
||||||
"columnNames": [
|
|
||||||
"name"
|
|
||||||
],
|
|
||||||
"orders": [],
|
|
||||||
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_categories_name` ON `${TABLE_NAME}` (`name`)"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"foreignKeys": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "category_recipe",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`category_id` INTEGER NOT NULL, `recipe_id` TEXT NOT NULL, PRIMARY KEY(`category_id`, `recipe_id`), FOREIGN KEY(`category_id`) REFERENCES `categories`(`local_id`) ON UPDATE CASCADE ON DELETE CASCADE , FOREIGN KEY(`recipe_id`) REFERENCES `recipe_summaries`(`remote_id`) ON UPDATE CASCADE ON DELETE CASCADE )",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "categoryId",
|
|
||||||
"columnName": "category_id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "recipeId",
|
|
||||||
"columnName": "recipe_id",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"category_id",
|
|
||||||
"recipe_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": false
|
|
||||||
},
|
|
||||||
"indices": [
|
|
||||||
{
|
|
||||||
"name": "index_category_recipe_category_id_recipe_id",
|
|
||||||
"unique": true,
|
|
||||||
"columnNames": [
|
|
||||||
"category_id",
|
|
||||||
"recipe_id"
|
|
||||||
],
|
|
||||||
"orders": [],
|
|
||||||
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_category_recipe_category_id_recipe_id` ON `${TABLE_NAME}` (`category_id`, `recipe_id`)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "index_category_recipe_recipe_id",
|
|
||||||
"unique": false,
|
|
||||||
"columnNames": [
|
|
||||||
"recipe_id"
|
|
||||||
],
|
|
||||||
"orders": [],
|
|
||||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_category_recipe_recipe_id` ON `${TABLE_NAME}` (`recipe_id`)"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"foreignKeys": [
|
|
||||||
{
|
|
||||||
"table": "categories",
|
|
||||||
"onDelete": "CASCADE",
|
|
||||||
"onUpdate": "CASCADE",
|
|
||||||
"columns": [
|
|
||||||
"category_id"
|
|
||||||
],
|
|
||||||
"referencedColumns": [
|
|
||||||
"local_id"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"table": "recipe_summaries",
|
|
||||||
"onDelete": "CASCADE",
|
|
||||||
"onUpdate": "CASCADE",
|
|
||||||
"columns": [
|
|
||||||
"recipe_id"
|
|
||||||
],
|
|
||||||
"referencedColumns": [
|
|
||||||
"remote_id"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "tags",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`local_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL)",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "localId",
|
|
||||||
"columnName": "local_id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "name",
|
|
||||||
"columnName": "name",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"local_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": true
|
|
||||||
},
|
|
||||||
"indices": [
|
|
||||||
{
|
|
||||||
"name": "index_tags_name",
|
|
||||||
"unique": true,
|
|
||||||
"columnNames": [
|
|
||||||
"name"
|
|
||||||
],
|
|
||||||
"orders": [],
|
|
||||||
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_tags_name` ON `${TABLE_NAME}` (`name`)"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"foreignKeys": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "tag_recipe",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`tag_id` INTEGER NOT NULL, `recipe_id` TEXT NOT NULL, PRIMARY KEY(`tag_id`, `recipe_id`), FOREIGN KEY(`tag_id`) REFERENCES `tags`(`local_id`) ON UPDATE CASCADE ON DELETE CASCADE , FOREIGN KEY(`recipe_id`) REFERENCES `recipe_summaries`(`remote_id`) ON UPDATE CASCADE ON DELETE CASCADE )",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "tagId",
|
|
||||||
"columnName": "tag_id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "recipeId",
|
|
||||||
"columnName": "recipe_id",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"tag_id",
|
|
||||||
"recipe_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": false
|
|
||||||
},
|
|
||||||
"indices": [
|
|
||||||
{
|
|
||||||
"name": "index_tag_recipe_recipe_id",
|
|
||||||
"unique": false,
|
|
||||||
"columnNames": [
|
|
||||||
"recipe_id"
|
|
||||||
],
|
|
||||||
"orders": [],
|
|
||||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_tag_recipe_recipe_id` ON `${TABLE_NAME}` (`recipe_id`)"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"foreignKeys": [
|
|
||||||
{
|
|
||||||
"table": "tags",
|
|
||||||
"onDelete": "CASCADE",
|
|
||||||
"onUpdate": "CASCADE",
|
|
||||||
"columns": [
|
|
||||||
"tag_id"
|
|
||||||
],
|
|
||||||
"referencedColumns": [
|
|
||||||
"local_id"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"table": "recipe_summaries",
|
|
||||||
"onDelete": "CASCADE",
|
|
||||||
"onUpdate": "CASCADE",
|
|
||||||
"columns": [
|
|
||||||
"recipe_id"
|
|
||||||
],
|
|
||||||
"referencedColumns": [
|
|
||||||
"remote_id"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "recipe_summaries",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`remote_id` TEXT NOT NULL, `name` TEXT NOT NULL, `slug` TEXT NOT NULL, `image` TEXT, `description` TEXT NOT NULL, `rating` INTEGER, `date_added` INTEGER NOT NULL, `date_updated` INTEGER NOT NULL, PRIMARY KEY(`remote_id`))",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "remoteId",
|
|
||||||
"columnName": "remote_id",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "name",
|
|
||||||
"columnName": "name",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "slug",
|
|
||||||
"columnName": "slug",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "image",
|
|
||||||
"columnName": "image",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "description",
|
|
||||||
"columnName": "description",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "rating",
|
|
||||||
"columnName": "rating",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "dateAdded",
|
|
||||||
"columnName": "date_added",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "dateUpdated",
|
|
||||||
"columnName": "date_updated",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"remote_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": false
|
|
||||||
},
|
|
||||||
"indices": [],
|
|
||||||
"foreignKeys": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "recipe",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`remote_id` TEXT NOT NULL, `recipe_yield` TEXT NOT NULL, PRIMARY KEY(`remote_id`))",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "remoteId",
|
|
||||||
"columnName": "remote_id",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "recipeYield",
|
|
||||||
"columnName": "recipe_yield",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"remote_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": false
|
|
||||||
},
|
|
||||||
"indices": [],
|
|
||||||
"foreignKeys": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "recipe_ingredient",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`local_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `recipe_id` TEXT NOT NULL, `title` TEXT NOT NULL, `note` TEXT NOT NULL, `unit` TEXT NOT NULL, `food` TEXT NOT NULL, `disable_amount` INTEGER NOT NULL, `quantity` REAL NOT NULL)",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "localId",
|
|
||||||
"columnName": "local_id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "recipeId",
|
|
||||||
"columnName": "recipe_id",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "title",
|
|
||||||
"columnName": "title",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "note",
|
|
||||||
"columnName": "note",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "unit",
|
|
||||||
"columnName": "unit",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "food",
|
|
||||||
"columnName": "food",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "disableAmount",
|
|
||||||
"columnName": "disable_amount",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "quantity",
|
|
||||||
"columnName": "quantity",
|
|
||||||
"affinity": "REAL",
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"local_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": true
|
|
||||||
},
|
|
||||||
"indices": [],
|
|
||||||
"foreignKeys": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "recipe_instruction",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`local_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `recipe_id` TEXT NOT NULL, `title` TEXT NOT NULL, `text` TEXT NOT NULL)",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "localId",
|
|
||||||
"columnName": "local_id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "recipeId",
|
|
||||||
"columnName": "recipe_id",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "title",
|
|
||||||
"columnName": "title",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "text",
|
|
||||||
"columnName": "text",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"local_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": true
|
|
||||||
},
|
|
||||||
"indices": [],
|
|
||||||
"foreignKeys": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"views": [],
|
|
||||||
"setupQueries": [
|
|
||||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
|
||||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '28c896eb34e95c0cff33148178252f72')"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,410 +0,0 @@
|
|||||||
{
|
|
||||||
"formatVersion": 1,
|
|
||||||
"database": {
|
|
||||||
"version": 4,
|
|
||||||
"identityHash": "13be83018f147e1f6e864790656da4a7",
|
|
||||||
"entities": [
|
|
||||||
{
|
|
||||||
"tableName": "categories",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`local_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL)",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "localId",
|
|
||||||
"columnName": "local_id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "name",
|
|
||||||
"columnName": "name",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"local_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": true
|
|
||||||
},
|
|
||||||
"indices": [
|
|
||||||
{
|
|
||||||
"name": "index_categories_name",
|
|
||||||
"unique": true,
|
|
||||||
"columnNames": [
|
|
||||||
"name"
|
|
||||||
],
|
|
||||||
"orders": [],
|
|
||||||
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_categories_name` ON `${TABLE_NAME}` (`name`)"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"foreignKeys": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "category_recipe",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`category_id` INTEGER NOT NULL, `recipe_id` TEXT NOT NULL, PRIMARY KEY(`category_id`, `recipe_id`), FOREIGN KEY(`category_id`) REFERENCES `categories`(`local_id`) ON UPDATE CASCADE ON DELETE CASCADE , FOREIGN KEY(`recipe_id`) REFERENCES `recipe_summaries`(`remote_id`) ON UPDATE CASCADE ON DELETE CASCADE )",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "categoryId",
|
|
||||||
"columnName": "category_id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "recipeId",
|
|
||||||
"columnName": "recipe_id",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"category_id",
|
|
||||||
"recipe_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": false
|
|
||||||
},
|
|
||||||
"indices": [
|
|
||||||
{
|
|
||||||
"name": "index_category_recipe_category_id_recipe_id",
|
|
||||||
"unique": true,
|
|
||||||
"columnNames": [
|
|
||||||
"category_id",
|
|
||||||
"recipe_id"
|
|
||||||
],
|
|
||||||
"orders": [],
|
|
||||||
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_category_recipe_category_id_recipe_id` ON `${TABLE_NAME}` (`category_id`, `recipe_id`)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "index_category_recipe_recipe_id",
|
|
||||||
"unique": false,
|
|
||||||
"columnNames": [
|
|
||||||
"recipe_id"
|
|
||||||
],
|
|
||||||
"orders": [],
|
|
||||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_category_recipe_recipe_id` ON `${TABLE_NAME}` (`recipe_id`)"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"foreignKeys": [
|
|
||||||
{
|
|
||||||
"table": "categories",
|
|
||||||
"onDelete": "CASCADE",
|
|
||||||
"onUpdate": "CASCADE",
|
|
||||||
"columns": [
|
|
||||||
"category_id"
|
|
||||||
],
|
|
||||||
"referencedColumns": [
|
|
||||||
"local_id"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"table": "recipe_summaries",
|
|
||||||
"onDelete": "CASCADE",
|
|
||||||
"onUpdate": "CASCADE",
|
|
||||||
"columns": [
|
|
||||||
"recipe_id"
|
|
||||||
],
|
|
||||||
"referencedColumns": [
|
|
||||||
"remote_id"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "tags",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`local_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL)",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "localId",
|
|
||||||
"columnName": "local_id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "name",
|
|
||||||
"columnName": "name",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"local_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": true
|
|
||||||
},
|
|
||||||
"indices": [
|
|
||||||
{
|
|
||||||
"name": "index_tags_name",
|
|
||||||
"unique": true,
|
|
||||||
"columnNames": [
|
|
||||||
"name"
|
|
||||||
],
|
|
||||||
"orders": [],
|
|
||||||
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_tags_name` ON `${TABLE_NAME}` (`name`)"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"foreignKeys": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "tag_recipe",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`tag_id` INTEGER NOT NULL, `recipe_id` TEXT NOT NULL, PRIMARY KEY(`tag_id`, `recipe_id`), FOREIGN KEY(`tag_id`) REFERENCES `tags`(`local_id`) ON UPDATE CASCADE ON DELETE CASCADE , FOREIGN KEY(`recipe_id`) REFERENCES `recipe_summaries`(`remote_id`) ON UPDATE CASCADE ON DELETE CASCADE )",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "tagId",
|
|
||||||
"columnName": "tag_id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "recipeId",
|
|
||||||
"columnName": "recipe_id",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"tag_id",
|
|
||||||
"recipe_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": false
|
|
||||||
},
|
|
||||||
"indices": [
|
|
||||||
{
|
|
||||||
"name": "index_tag_recipe_recipe_id",
|
|
||||||
"unique": false,
|
|
||||||
"columnNames": [
|
|
||||||
"recipe_id"
|
|
||||||
],
|
|
||||||
"orders": [],
|
|
||||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_tag_recipe_recipe_id` ON `${TABLE_NAME}` (`recipe_id`)"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"foreignKeys": [
|
|
||||||
{
|
|
||||||
"table": "tags",
|
|
||||||
"onDelete": "CASCADE",
|
|
||||||
"onUpdate": "CASCADE",
|
|
||||||
"columns": [
|
|
||||||
"tag_id"
|
|
||||||
],
|
|
||||||
"referencedColumns": [
|
|
||||||
"local_id"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"table": "recipe_summaries",
|
|
||||||
"onDelete": "CASCADE",
|
|
||||||
"onUpdate": "CASCADE",
|
|
||||||
"columns": [
|
|
||||||
"recipe_id"
|
|
||||||
],
|
|
||||||
"referencedColumns": [
|
|
||||||
"remote_id"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "recipe_summaries",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`remote_id` TEXT NOT NULL, `name` TEXT NOT NULL, `slug` TEXT NOT NULL, `image` TEXT, `description` TEXT NOT NULL, `rating` INTEGER, `date_added` INTEGER NOT NULL, `date_updated` INTEGER NOT NULL, `image_id` TEXT, PRIMARY KEY(`remote_id`))",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "remoteId",
|
|
||||||
"columnName": "remote_id",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "name",
|
|
||||||
"columnName": "name",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "slug",
|
|
||||||
"columnName": "slug",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "image",
|
|
||||||
"columnName": "image",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "description",
|
|
||||||
"columnName": "description",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "rating",
|
|
||||||
"columnName": "rating",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "dateAdded",
|
|
||||||
"columnName": "date_added",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "dateUpdated",
|
|
||||||
"columnName": "date_updated",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "imageId",
|
|
||||||
"columnName": "image_id",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"remote_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": false
|
|
||||||
},
|
|
||||||
"indices": [],
|
|
||||||
"foreignKeys": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "recipe",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`remote_id` TEXT NOT NULL, `recipe_yield` TEXT NOT NULL, PRIMARY KEY(`remote_id`))",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "remoteId",
|
|
||||||
"columnName": "remote_id",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "recipeYield",
|
|
||||||
"columnName": "recipe_yield",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"remote_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": false
|
|
||||||
},
|
|
||||||
"indices": [],
|
|
||||||
"foreignKeys": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "recipe_ingredient",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`local_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `recipe_id` TEXT NOT NULL, `title` TEXT NOT NULL, `note` TEXT NOT NULL, `unit` TEXT NOT NULL, `food` TEXT NOT NULL, `disable_amount` INTEGER NOT NULL, `quantity` REAL NOT NULL)",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "localId",
|
|
||||||
"columnName": "local_id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "recipeId",
|
|
||||||
"columnName": "recipe_id",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "title",
|
|
||||||
"columnName": "title",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "note",
|
|
||||||
"columnName": "note",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "unit",
|
|
||||||
"columnName": "unit",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "food",
|
|
||||||
"columnName": "food",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "disableAmount",
|
|
||||||
"columnName": "disable_amount",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "quantity",
|
|
||||||
"columnName": "quantity",
|
|
||||||
"affinity": "REAL",
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"local_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": true
|
|
||||||
},
|
|
||||||
"indices": [],
|
|
||||||
"foreignKeys": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "recipe_instruction",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`local_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `recipe_id` TEXT NOT NULL, `title` TEXT NOT NULL, `text` TEXT NOT NULL)",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "localId",
|
|
||||||
"columnName": "local_id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "recipeId",
|
|
||||||
"columnName": "recipe_id",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "title",
|
|
||||||
"columnName": "title",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "text",
|
|
||||||
"columnName": "text",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"local_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": true
|
|
||||||
},
|
|
||||||
"indices": [],
|
|
||||||
"foreignKeys": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"views": [],
|
|
||||||
"setupQueries": [
|
|
||||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
|
||||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '13be83018f147e1f6e864790656da4a7')"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,374 +0,0 @@
|
|||||||
{
|
|
||||||
"formatVersion": 1,
|
|
||||||
"database": {
|
|
||||||
"version": 5,
|
|
||||||
"identityHash": "e75a1e16503fdf60c62b7f9d17ec0bc6",
|
|
||||||
"entities": [
|
|
||||||
{
|
|
||||||
"tableName": "categories",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`local_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL)",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "localId",
|
|
||||||
"columnName": "local_id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "name",
|
|
||||||
"columnName": "name",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"local_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": true
|
|
||||||
},
|
|
||||||
"indices": [
|
|
||||||
{
|
|
||||||
"name": "index_categories_name",
|
|
||||||
"unique": true,
|
|
||||||
"columnNames": [
|
|
||||||
"name"
|
|
||||||
],
|
|
||||||
"orders": [],
|
|
||||||
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_categories_name` ON `${TABLE_NAME}` (`name`)"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"foreignKeys": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "category_recipe",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`category_id` INTEGER NOT NULL, `recipe_id` TEXT NOT NULL, PRIMARY KEY(`category_id`, `recipe_id`), FOREIGN KEY(`category_id`) REFERENCES `categories`(`local_id`) ON UPDATE CASCADE ON DELETE CASCADE , FOREIGN KEY(`recipe_id`) REFERENCES `recipe_summaries`(`remote_id`) ON UPDATE CASCADE ON DELETE CASCADE )",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "categoryId",
|
|
||||||
"columnName": "category_id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "recipeId",
|
|
||||||
"columnName": "recipe_id",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"category_id",
|
|
||||||
"recipe_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": false
|
|
||||||
},
|
|
||||||
"indices": [
|
|
||||||
{
|
|
||||||
"name": "index_category_recipe_category_id_recipe_id",
|
|
||||||
"unique": true,
|
|
||||||
"columnNames": [
|
|
||||||
"category_id",
|
|
||||||
"recipe_id"
|
|
||||||
],
|
|
||||||
"orders": [],
|
|
||||||
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_category_recipe_category_id_recipe_id` ON `${TABLE_NAME}` (`category_id`, `recipe_id`)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "index_category_recipe_recipe_id",
|
|
||||||
"unique": false,
|
|
||||||
"columnNames": [
|
|
||||||
"recipe_id"
|
|
||||||
],
|
|
||||||
"orders": [],
|
|
||||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_category_recipe_recipe_id` ON `${TABLE_NAME}` (`recipe_id`)"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"foreignKeys": [
|
|
||||||
{
|
|
||||||
"table": "categories",
|
|
||||||
"onDelete": "CASCADE",
|
|
||||||
"onUpdate": "CASCADE",
|
|
||||||
"columns": [
|
|
||||||
"category_id"
|
|
||||||
],
|
|
||||||
"referencedColumns": [
|
|
||||||
"local_id"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"table": "recipe_summaries",
|
|
||||||
"onDelete": "CASCADE",
|
|
||||||
"onUpdate": "CASCADE",
|
|
||||||
"columns": [
|
|
||||||
"recipe_id"
|
|
||||||
],
|
|
||||||
"referencedColumns": [
|
|
||||||
"remote_id"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "tags",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`local_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL)",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "localId",
|
|
||||||
"columnName": "local_id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "name",
|
|
||||||
"columnName": "name",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"local_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": true
|
|
||||||
},
|
|
||||||
"indices": [
|
|
||||||
{
|
|
||||||
"name": "index_tags_name",
|
|
||||||
"unique": true,
|
|
||||||
"columnNames": [
|
|
||||||
"name"
|
|
||||||
],
|
|
||||||
"orders": [],
|
|
||||||
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_tags_name` ON `${TABLE_NAME}` (`name`)"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"foreignKeys": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "tag_recipe",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`tag_id` INTEGER NOT NULL, `recipe_id` TEXT NOT NULL, PRIMARY KEY(`tag_id`, `recipe_id`), FOREIGN KEY(`tag_id`) REFERENCES `tags`(`local_id`) ON UPDATE CASCADE ON DELETE CASCADE , FOREIGN KEY(`recipe_id`) REFERENCES `recipe_summaries`(`remote_id`) ON UPDATE CASCADE ON DELETE CASCADE )",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "tagId",
|
|
||||||
"columnName": "tag_id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "recipeId",
|
|
||||||
"columnName": "recipe_id",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"tag_id",
|
|
||||||
"recipe_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": false
|
|
||||||
},
|
|
||||||
"indices": [
|
|
||||||
{
|
|
||||||
"name": "index_tag_recipe_recipe_id",
|
|
||||||
"unique": false,
|
|
||||||
"columnNames": [
|
|
||||||
"recipe_id"
|
|
||||||
],
|
|
||||||
"orders": [],
|
|
||||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_tag_recipe_recipe_id` ON `${TABLE_NAME}` (`recipe_id`)"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"foreignKeys": [
|
|
||||||
{
|
|
||||||
"table": "tags",
|
|
||||||
"onDelete": "CASCADE",
|
|
||||||
"onUpdate": "CASCADE",
|
|
||||||
"columns": [
|
|
||||||
"tag_id"
|
|
||||||
],
|
|
||||||
"referencedColumns": [
|
|
||||||
"local_id"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"table": "recipe_summaries",
|
|
||||||
"onDelete": "CASCADE",
|
|
||||||
"onUpdate": "CASCADE",
|
|
||||||
"columns": [
|
|
||||||
"recipe_id"
|
|
||||||
],
|
|
||||||
"referencedColumns": [
|
|
||||||
"remote_id"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "recipe_summaries",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`remote_id` TEXT NOT NULL, `name` TEXT NOT NULL, `slug` TEXT NOT NULL, `image` TEXT, `description` TEXT NOT NULL, `rating` INTEGER, `date_added` INTEGER NOT NULL, `date_updated` INTEGER NOT NULL, `image_id` TEXT, PRIMARY KEY(`remote_id`))",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "remoteId",
|
|
||||||
"columnName": "remote_id",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "name",
|
|
||||||
"columnName": "name",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "slug",
|
|
||||||
"columnName": "slug",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "image",
|
|
||||||
"columnName": "image",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "description",
|
|
||||||
"columnName": "description",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "rating",
|
|
||||||
"columnName": "rating",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "dateAdded",
|
|
||||||
"columnName": "date_added",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "dateUpdated",
|
|
||||||
"columnName": "date_updated",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "imageId",
|
|
||||||
"columnName": "image_id",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"remote_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": false
|
|
||||||
},
|
|
||||||
"indices": [],
|
|
||||||
"foreignKeys": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "recipe",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`remote_id` TEXT NOT NULL, `recipe_yield` TEXT NOT NULL, PRIMARY KEY(`remote_id`))",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "remoteId",
|
|
||||||
"columnName": "remote_id",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "recipeYield",
|
|
||||||
"columnName": "recipe_yield",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"remote_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": false
|
|
||||||
},
|
|
||||||
"indices": [],
|
|
||||||
"foreignKeys": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "recipe_ingredient",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`local_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `recipe_id` TEXT NOT NULL, `note` TEXT NOT NULL)",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "localId",
|
|
||||||
"columnName": "local_id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "recipeId",
|
|
||||||
"columnName": "recipe_id",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "note",
|
|
||||||
"columnName": "note",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"local_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": true
|
|
||||||
},
|
|
||||||
"indices": [],
|
|
||||||
"foreignKeys": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "recipe_instruction",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`local_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `recipe_id` TEXT NOT NULL, `text` TEXT NOT NULL)",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "localId",
|
|
||||||
"columnName": "local_id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "recipeId",
|
|
||||||
"columnName": "recipe_id",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "text",
|
|
||||||
"columnName": "text",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"local_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": true
|
|
||||||
},
|
|
||||||
"indices": [],
|
|
||||||
"foreignKeys": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"views": [],
|
|
||||||
"setupQueries": [
|
|
||||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
|
||||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'e75a1e16503fdf60c62b7f9d17ec0bc6')"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,160 +0,0 @@
|
|||||||
{
|
|
||||||
"formatVersion": 1,
|
|
||||||
"database": {
|
|
||||||
"version": 6,
|
|
||||||
"identityHash": "f6e28dd617e4d4a6843a7865c9da736d",
|
|
||||||
"entities": [
|
|
||||||
{
|
|
||||||
"tableName": "recipe_summaries",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`remote_id` TEXT NOT NULL, `name` TEXT NOT NULL, `slug` TEXT NOT NULL, `description` TEXT NOT NULL, `date_added` INTEGER NOT NULL, `date_updated` INTEGER NOT NULL, `image_id` TEXT, PRIMARY KEY(`remote_id`))",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "remoteId",
|
|
||||||
"columnName": "remote_id",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "name",
|
|
||||||
"columnName": "name",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "slug",
|
|
||||||
"columnName": "slug",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "description",
|
|
||||||
"columnName": "description",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "dateAdded",
|
|
||||||
"columnName": "date_added",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "dateUpdated",
|
|
||||||
"columnName": "date_updated",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "imageId",
|
|
||||||
"columnName": "image_id",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"remote_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": false
|
|
||||||
},
|
|
||||||
"indices": [],
|
|
||||||
"foreignKeys": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "recipe",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`remote_id` TEXT NOT NULL, `recipe_yield` TEXT NOT NULL, PRIMARY KEY(`remote_id`))",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "remoteId",
|
|
||||||
"columnName": "remote_id",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "recipeYield",
|
|
||||||
"columnName": "recipe_yield",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"remote_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": false
|
|
||||||
},
|
|
||||||
"indices": [],
|
|
||||||
"foreignKeys": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "recipe_ingredient",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`local_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `recipe_id` TEXT NOT NULL, `note` TEXT NOT NULL)",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "localId",
|
|
||||||
"columnName": "local_id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "recipeId",
|
|
||||||
"columnName": "recipe_id",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "note",
|
|
||||||
"columnName": "note",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"local_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": true
|
|
||||||
},
|
|
||||||
"indices": [],
|
|
||||||
"foreignKeys": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "recipe_instruction",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`local_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `recipe_id` TEXT NOT NULL, `text` TEXT NOT NULL)",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "localId",
|
|
||||||
"columnName": "local_id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "recipeId",
|
|
||||||
"columnName": "recipe_id",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "text",
|
|
||||||
"columnName": "text",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"local_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": true
|
|
||||||
},
|
|
||||||
"indices": [],
|
|
||||||
"foreignKeys": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"views": [],
|
|
||||||
"setupQueries": [
|
|
||||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
|
||||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'f6e28dd617e4d4a6843a7865c9da736d')"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,191 +0,0 @@
|
|||||||
{
|
|
||||||
"formatVersion": 1,
|
|
||||||
"database": {
|
|
||||||
"version": 7,
|
|
||||||
"identityHash": "d2679aea13d3c18e58c537164f70e249",
|
|
||||||
"entities": [
|
|
||||||
{
|
|
||||||
"tableName": "recipe_summaries",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`remote_id` TEXT NOT NULL, `name` TEXT NOT NULL, `slug` TEXT NOT NULL, `description` TEXT NOT NULL, `date_added` INTEGER NOT NULL, `date_updated` INTEGER NOT NULL, `image_id` TEXT, PRIMARY KEY(`remote_id`))",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "remoteId",
|
|
||||||
"columnName": "remote_id",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "name",
|
|
||||||
"columnName": "name",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "slug",
|
|
||||||
"columnName": "slug",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "description",
|
|
||||||
"columnName": "description",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "dateAdded",
|
|
||||||
"columnName": "date_added",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "dateUpdated",
|
|
||||||
"columnName": "date_updated",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "imageId",
|
|
||||||
"columnName": "image_id",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"remote_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": false
|
|
||||||
},
|
|
||||||
"indices": [],
|
|
||||||
"foreignKeys": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "recipe",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`remote_id` TEXT NOT NULL, `recipe_yield` TEXT NOT NULL, `disable_amounts` INTEGER NOT NULL DEFAULT true, PRIMARY KEY(`remote_id`))",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "remoteId",
|
|
||||||
"columnName": "remote_id",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "recipeYield",
|
|
||||||
"columnName": "recipe_yield",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "disableAmounts",
|
|
||||||
"columnName": "disable_amounts",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "true"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"remote_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": false
|
|
||||||
},
|
|
||||||
"indices": [],
|
|
||||||
"foreignKeys": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "recipe_ingredient",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`local_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `recipe_id` TEXT NOT NULL, `note` TEXT NOT NULL, `food` TEXT, `unit` TEXT, `quantity` REAL, `title` TEXT)",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "localId",
|
|
||||||
"columnName": "local_id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "recipeId",
|
|
||||||
"columnName": "recipe_id",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "note",
|
|
||||||
"columnName": "note",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "food",
|
|
||||||
"columnName": "food",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "unit",
|
|
||||||
"columnName": "unit",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "quantity",
|
|
||||||
"columnName": "quantity",
|
|
||||||
"affinity": "REAL",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "title",
|
|
||||||
"columnName": "title",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"local_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": true
|
|
||||||
},
|
|
||||||
"indices": [],
|
|
||||||
"foreignKeys": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "recipe_instruction",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`local_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `recipe_id` TEXT NOT NULL, `text` TEXT NOT NULL)",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "localId",
|
|
||||||
"columnName": "local_id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "recipeId",
|
|
||||||
"columnName": "recipe_id",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "text",
|
|
||||||
"columnName": "text",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"local_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": true
|
|
||||||
},
|
|
||||||
"indices": [],
|
|
||||||
"foreignKeys": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"views": [],
|
|
||||||
"setupQueries": [
|
|
||||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
|
||||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'd2679aea13d3c18e58c537164f70e249')"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,198 +0,0 @@
|
|||||||
{
|
|
||||||
"formatVersion": 1,
|
|
||||||
"database": {
|
|
||||||
"version": 8,
|
|
||||||
"identityHash": "793673e401425db36544918dae6bf4c1",
|
|
||||||
"entities": [
|
|
||||||
{
|
|
||||||
"tableName": "recipe_summaries",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`remote_id` TEXT NOT NULL, `name` TEXT NOT NULL, `slug` TEXT NOT NULL, `description` TEXT NOT NULL, `date_added` INTEGER NOT NULL, `date_updated` INTEGER NOT NULL, `image_id` TEXT, `is_favorite` INTEGER NOT NULL DEFAULT false, PRIMARY KEY(`remote_id`))",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "remoteId",
|
|
||||||
"columnName": "remote_id",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "name",
|
|
||||||
"columnName": "name",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "slug",
|
|
||||||
"columnName": "slug",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "description",
|
|
||||||
"columnName": "description",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "dateAdded",
|
|
||||||
"columnName": "date_added",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "dateUpdated",
|
|
||||||
"columnName": "date_updated",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "imageId",
|
|
||||||
"columnName": "image_id",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "isFavorite",
|
|
||||||
"columnName": "is_favorite",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "false"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"remote_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": false
|
|
||||||
},
|
|
||||||
"indices": [],
|
|
||||||
"foreignKeys": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "recipe",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`remote_id` TEXT NOT NULL, `recipe_yield` TEXT NOT NULL, `disable_amounts` INTEGER NOT NULL DEFAULT true, PRIMARY KEY(`remote_id`))",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "remoteId",
|
|
||||||
"columnName": "remote_id",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "recipeYield",
|
|
||||||
"columnName": "recipe_yield",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "disableAmounts",
|
|
||||||
"columnName": "disable_amounts",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true,
|
|
||||||
"defaultValue": "true"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"remote_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": false
|
|
||||||
},
|
|
||||||
"indices": [],
|
|
||||||
"foreignKeys": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "recipe_ingredient",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`local_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `recipe_id` TEXT NOT NULL, `note` TEXT NOT NULL, `food` TEXT, `unit` TEXT, `quantity` REAL, `title` TEXT)",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "localId",
|
|
||||||
"columnName": "local_id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "recipeId",
|
|
||||||
"columnName": "recipe_id",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "note",
|
|
||||||
"columnName": "note",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "food",
|
|
||||||
"columnName": "food",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "unit",
|
|
||||||
"columnName": "unit",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "quantity",
|
|
||||||
"columnName": "quantity",
|
|
||||||
"affinity": "REAL",
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "title",
|
|
||||||
"columnName": "title",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"local_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": true
|
|
||||||
},
|
|
||||||
"indices": [],
|
|
||||||
"foreignKeys": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tableName": "recipe_instruction",
|
|
||||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`local_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `recipe_id` TEXT NOT NULL, `text` TEXT NOT NULL)",
|
|
||||||
"fields": [
|
|
||||||
{
|
|
||||||
"fieldPath": "localId",
|
|
||||||
"columnName": "local_id",
|
|
||||||
"affinity": "INTEGER",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "recipeId",
|
|
||||||
"columnName": "recipe_id",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fieldPath": "text",
|
|
||||||
"columnName": "text",
|
|
||||||
"affinity": "TEXT",
|
|
||||||
"notNull": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"primaryKey": {
|
|
||||||
"columnNames": [
|
|
||||||
"local_id"
|
|
||||||
],
|
|
||||||
"autoGenerate": true
|
|
||||||
},
|
|
||||||
"indices": [],
|
|
||||||
"foreignKeys": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"views": [],
|
|
||||||
"setupQueries": [
|
|
||||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
|
||||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '793673e401425db36544918dae6bf4c1')"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,45 +1,20 @@
|
|||||||
package gq.kirmanak.mealient.database
|
package gq.kirmanak.mealient.database
|
||||||
|
|
||||||
import androidx.room.*
|
import androidx.room.*
|
||||||
import androidx.room.migration.AutoMigrationSpec
|
|
||||||
import gq.kirmanak.mealient.database.recipe.RecipeDao
|
import gq.kirmanak.mealient.database.recipe.RecipeDao
|
||||||
import gq.kirmanak.mealient.database.recipe.entity.*
|
import gq.kirmanak.mealient.database.recipe.entity.*
|
||||||
|
|
||||||
@Database(
|
@Database(
|
||||||
version = 8,
|
version = 10,
|
||||||
entities = [
|
entities = [
|
||||||
RecipeSummaryEntity::class,
|
RecipeSummaryEntity::class,
|
||||||
RecipeEntity::class,
|
RecipeEntity::class,
|
||||||
RecipeIngredientEntity::class,
|
RecipeIngredientEntity::class,
|
||||||
RecipeInstructionEntity::class,
|
RecipeInstructionEntity::class,
|
||||||
],
|
|
||||||
exportSchema = true,
|
|
||||||
autoMigrations = [
|
|
||||||
AutoMigration(from = 1, to = 2),
|
|
||||||
AutoMigration(from = 3, to = 4),
|
|
||||||
AutoMigration(from = 4, to = 5, spec = AppDb.From4To5Migration::class),
|
|
||||||
AutoMigration(from = 5, to = 6, spec = AppDb.From5To6Migration::class),
|
|
||||||
AutoMigration(from = 6, to = 7),
|
|
||||||
AutoMigration(from = 7, to = 8),
|
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
@TypeConverters(RoomTypeConverters::class)
|
@TypeConverters(RoomTypeConverters::class)
|
||||||
abstract class AppDb : RoomDatabase() {
|
internal abstract class AppDb : RoomDatabase() {
|
||||||
|
|
||||||
abstract fun recipeDao(): RecipeDao
|
abstract fun recipeDao(): RecipeDao
|
||||||
|
|
||||||
@DeleteColumn(tableName = "recipe_instruction", columnName = "title")
|
|
||||||
@DeleteColumn(tableName = "recipe_ingredient", columnName = "title")
|
|
||||||
@DeleteColumn(tableName = "recipe_ingredient", columnName = "unit")
|
|
||||||
@DeleteColumn(tableName = "recipe_ingredient", columnName = "food")
|
|
||||||
@DeleteColumn(tableName = "recipe_ingredient", columnName = "disable_amount")
|
|
||||||
@DeleteColumn(tableName = "recipe_ingredient", columnName = "quantity")
|
|
||||||
class From4To5Migration : AutoMigrationSpec
|
|
||||||
|
|
||||||
@DeleteColumn(tableName = "recipe_summaries", columnName = "image")
|
|
||||||
@DeleteColumn(tableName = "recipe_summaries", columnName = "rating")
|
|
||||||
@DeleteTable(tableName = "tag_recipe")
|
|
||||||
@DeleteTable(tableName = "tags")
|
|
||||||
@DeleteTable(tableName = "categories")
|
|
||||||
@DeleteTable(tableName = "category_recipe")
|
|
||||||
class From5To6Migration : AutoMigrationSpec
|
|
||||||
}
|
}
|
||||||
@@ -2,23 +2,35 @@ package gq.kirmanak.mealient.database
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.room.Room
|
import androidx.room.Room
|
||||||
|
import dagger.Binds
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
import dagger.hilt.InstallIn
|
import dagger.hilt.InstallIn
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import dagger.hilt.components.SingletonComponent
|
import dagger.hilt.components.SingletonComponent
|
||||||
|
import gq.kirmanak.mealient.database.recipe.RecipeDao
|
||||||
|
import gq.kirmanak.mealient.database.recipe.RecipeStorage
|
||||||
|
import gq.kirmanak.mealient.database.recipe.RecipeStorageImpl
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
@InstallIn(SingletonComponent::class)
|
@InstallIn(SingletonComponent::class)
|
||||||
interface DatabaseModule {
|
internal interface DatabaseModule {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
fun createDb(@ApplicationContext context: Context): AppDb =
|
fun createDb(@ApplicationContext context: Context): AppDb =
|
||||||
Room.databaseBuilder(context, AppDb::class.java, "app.db")
|
Room.databaseBuilder(context, AppDb::class.java, "app.db")
|
||||||
.fallbackToDestructiveMigrationFrom(2)
|
.fallbackToDestructiveMigration()
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideRecipeDao(db: AppDb): RecipeDao = db.recipeDao()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@Singleton
|
||||||
|
fun provideRecipeStorage(recipeStorageImpl: RecipeStorageImpl): RecipeStorage
|
||||||
}
|
}
|
||||||
@@ -5,25 +5,30 @@ import androidx.room.*
|
|||||||
import gq.kirmanak.mealient.database.recipe.entity.*
|
import gq.kirmanak.mealient.database.recipe.entity.*
|
||||||
|
|
||||||
@Dao
|
@Dao
|
||||||
interface RecipeDao {
|
internal interface RecipeDao {
|
||||||
@Query("SELECT * FROM recipe_summaries ORDER BY date_added DESC")
|
@Query("SELECT * FROM recipe_summaries ORDER BY recipe_summaries_date_added DESC")
|
||||||
fun queryRecipesByPages(): PagingSource<Int, RecipeSummaryEntity>
|
fun queryRecipesByPages(): PagingSource<Int, RecipeSummaryEntity>
|
||||||
|
|
||||||
@Query("SELECT * FROM recipe_summaries WHERE recipe_summaries.name LIKE '%' || :query || '%' ORDER BY date_added DESC")
|
@Query("SELECT * FROM recipe_summaries WHERE recipe_summaries_name LIKE '%' || :query || '%' ORDER BY recipe_summaries_date_added DESC")
|
||||||
fun queryRecipesByPages(query: String): PagingSource<Int, RecipeSummaryEntity>
|
fun queryRecipesByPages(query: String): PagingSource<Int, RecipeSummaryEntity>
|
||||||
|
|
||||||
|
@Transaction
|
||||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||||
suspend fun insertRecipes(recipeSummaryEntity: Iterable<RecipeSummaryEntity>)
|
suspend fun insertRecipeSummaries(recipeSummaryEntity: Iterable<RecipeSummaryEntity>)
|
||||||
|
|
||||||
|
@Transaction
|
||||||
@Query("DELETE FROM recipe_summaries")
|
@Query("DELETE FROM recipe_summaries")
|
||||||
suspend fun removeAllRecipes()
|
suspend fun removeAllRecipes()
|
||||||
|
|
||||||
@Query("SELECT * FROM recipe_summaries ORDER BY date_updated DESC")
|
@Query("SELECT * FROM recipe_summaries ORDER BY recipe_summaries_date_added DESC")
|
||||||
suspend fun queryAllRecipes(): List<RecipeSummaryEntity>
|
suspend fun queryAllRecipes(): List<RecipeSummaryEntity>
|
||||||
|
|
||||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||||
suspend fun insertRecipe(recipe: RecipeEntity)
|
suspend fun insertRecipe(recipe: RecipeEntity)
|
||||||
|
|
||||||
|
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||||
|
suspend fun insertRecipes(recipe: List<RecipeEntity>)
|
||||||
|
|
||||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||||
suspend fun insertRecipeInstructions(instructions: List<RecipeInstructionEntity>)
|
suspend fun insertRecipeInstructions(instructions: List<RecipeInstructionEntity>)
|
||||||
|
|
||||||
@@ -32,19 +37,25 @@ interface RecipeDao {
|
|||||||
|
|
||||||
@Transaction
|
@Transaction
|
||||||
@SuppressWarnings(RoomWarnings.CURSOR_MISMATCH) // The lint is wrong, the columns are actually used
|
@SuppressWarnings(RoomWarnings.CURSOR_MISMATCH) // The lint is wrong, the columns are actually used
|
||||||
@Query("SELECT * FROM recipe JOIN recipe_summaries ON recipe.remote_id = recipe_summaries.remote_id JOIN recipe_ingredient ON recipe_ingredient.recipe_id = recipe.remote_id JOIN recipe_instruction ON recipe_instruction.recipe_id = recipe.remote_id WHERE recipe.remote_id = :recipeId")
|
@Query(
|
||||||
suspend fun queryFullRecipeInfo(recipeId: String): FullRecipeEntity?
|
"SELECT * FROM recipe " +
|
||||||
|
"JOIN recipe_summaries USING(recipe_id) " +
|
||||||
|
"JOIN recipe_ingredient USING(recipe_id) " +
|
||||||
|
"JOIN recipe_instruction USING(recipe_id) " +
|
||||||
|
"WHERE recipe.recipe_id = :recipeId"
|
||||||
|
)
|
||||||
|
suspend fun queryFullRecipeInfo(recipeId: String): RecipeWithSummaryAndIngredientsAndInstructions?
|
||||||
|
|
||||||
@Query("DELETE FROM recipe_ingredient WHERE recipe_id = :recipeId")
|
@Query("DELETE FROM recipe_ingredient WHERE recipe_id IN (:recipeIds)")
|
||||||
suspend fun deleteRecipeIngredients(recipeId: String)
|
suspend fun deleteRecipeIngredients(vararg recipeIds: String)
|
||||||
|
|
||||||
@Query("DELETE FROM recipe_instruction WHERE recipe_id = :recipeId")
|
@Query("DELETE FROM recipe_instruction WHERE recipe_id IN (:recipeIds)")
|
||||||
suspend fun deleteRecipeInstructions(recipeId: String)
|
suspend fun deleteRecipeInstructions(vararg recipeIds: String)
|
||||||
|
|
||||||
@Query("UPDATE recipe_summaries SET is_favorite = 1 WHERE slug IN (:favorites)")
|
@Query("UPDATE recipe_summaries SET recipe_summaries_is_favorite = 1 WHERE recipe_summaries_slug IN (:favorites)")
|
||||||
suspend fun setFavorite(favorites: List<String>)
|
suspend fun setFavorite(favorites: List<String>)
|
||||||
|
|
||||||
@Query("UPDATE recipe_summaries SET is_favorite = 0 WHERE slug NOT IN (:favorites)")
|
@Query("UPDATE recipe_summaries SET recipe_summaries_is_favorite = 0 WHERE recipe_summaries_slug NOT IN (:favorites)")
|
||||||
suspend fun setNonFavorite(favorites: List<String>)
|
suspend fun setNonFavorite(favorites: List<String>)
|
||||||
|
|
||||||
@Delete
|
@Delete
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package gq.kirmanak.mealient.database.recipe
|
||||||
|
|
||||||
|
import androidx.paging.PagingSource
|
||||||
|
import gq.kirmanak.mealient.database.recipe.entity.RecipeEntity
|
||||||
|
import gq.kirmanak.mealient.database.recipe.entity.RecipeIngredientEntity
|
||||||
|
import gq.kirmanak.mealient.database.recipe.entity.RecipeInstructionEntity
|
||||||
|
import gq.kirmanak.mealient.database.recipe.entity.RecipeSummaryEntity
|
||||||
|
import gq.kirmanak.mealient.database.recipe.entity.RecipeWithSummaryAndIngredientsAndInstructions
|
||||||
|
|
||||||
|
interface RecipeStorage {
|
||||||
|
suspend fun saveRecipes(recipes: List<RecipeSummaryEntity>)
|
||||||
|
|
||||||
|
fun queryRecipes(query: String?): PagingSource<Int, RecipeSummaryEntity>
|
||||||
|
|
||||||
|
suspend fun refreshAll(recipes: List<RecipeSummaryEntity>)
|
||||||
|
|
||||||
|
suspend fun clearAllLocalData()
|
||||||
|
|
||||||
|
suspend fun saveRecipeInfo(
|
||||||
|
recipe: RecipeEntity,
|
||||||
|
ingredients: List<RecipeIngredientEntity>,
|
||||||
|
instructions: List<RecipeInstructionEntity>
|
||||||
|
)
|
||||||
|
|
||||||
|
suspend fun queryRecipeInfo(recipeId: String): RecipeWithSummaryAndIngredientsAndInstructions?
|
||||||
|
|
||||||
|
suspend fun updateFavoriteRecipes(favorites: List<String>)
|
||||||
|
|
||||||
|
suspend fun deleteRecipe(entity: RecipeSummaryEntity)
|
||||||
|
}
|
||||||
@@ -1,29 +1,27 @@
|
|||||||
package gq.kirmanak.mealient.data.recipes.db
|
package gq.kirmanak.mealient.database.recipe
|
||||||
|
|
||||||
import androidx.paging.PagingSource
|
import androidx.paging.PagingSource
|
||||||
import androidx.room.withTransaction
|
import androidx.room.withTransaction
|
||||||
import gq.kirmanak.mealient.data.recipes.network.FullRecipeInfo
|
|
||||||
import gq.kirmanak.mealient.database.AppDb
|
import gq.kirmanak.mealient.database.AppDb
|
||||||
import gq.kirmanak.mealient.database.recipe.RecipeDao
|
import gq.kirmanak.mealient.database.recipe.entity.RecipeEntity
|
||||||
import gq.kirmanak.mealient.database.recipe.entity.FullRecipeEntity
|
import gq.kirmanak.mealient.database.recipe.entity.RecipeIngredientEntity
|
||||||
|
import gq.kirmanak.mealient.database.recipe.entity.RecipeInstructionEntity
|
||||||
import gq.kirmanak.mealient.database.recipe.entity.RecipeSummaryEntity
|
import gq.kirmanak.mealient.database.recipe.entity.RecipeSummaryEntity
|
||||||
import gq.kirmanak.mealient.extensions.toRecipeEntity
|
import gq.kirmanak.mealient.database.recipe.entity.RecipeWithSummaryAndIngredientsAndInstructions
|
||||||
import gq.kirmanak.mealient.extensions.toRecipeIngredientEntity
|
|
||||||
import gq.kirmanak.mealient.extensions.toRecipeInstructionEntity
|
|
||||||
import gq.kirmanak.mealient.logging.Logger
|
import gq.kirmanak.mealient.logging.Logger
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class RecipeStorageImpl @Inject constructor(
|
internal class RecipeStorageImpl @Inject constructor(
|
||||||
private val db: AppDb,
|
private val db: AppDb,
|
||||||
private val logger: Logger,
|
private val logger: Logger,
|
||||||
|
private val recipeDao: RecipeDao,
|
||||||
) : RecipeStorage {
|
) : RecipeStorage {
|
||||||
private val recipeDao: RecipeDao by lazy { db.recipeDao() }
|
|
||||||
|
|
||||||
override suspend fun saveRecipes(recipes: List<RecipeSummaryEntity>) {
|
override suspend fun saveRecipes(recipes: List<RecipeSummaryEntity>) {
|
||||||
logger.v { "saveRecipes() called with $recipes" }
|
logger.v { "saveRecipes() called with $recipes" }
|
||||||
db.withTransaction { recipeDao.insertRecipes(recipes) }
|
recipeDao.insertRecipeSummaries(recipes)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun queryRecipes(query: String?): PagingSource<Int, RecipeSummaryEntity> {
|
override fun queryRecipes(query: String?): PagingSource<Int, RecipeSummaryEntity> {
|
||||||
@@ -42,31 +40,27 @@ class RecipeStorageImpl @Inject constructor(
|
|||||||
|
|
||||||
override suspend fun clearAllLocalData() {
|
override suspend fun clearAllLocalData() {
|
||||||
logger.v { "clearAllLocalData() called" }
|
logger.v { "clearAllLocalData() called" }
|
||||||
db.withTransaction {
|
recipeDao.removeAllRecipes()
|
||||||
recipeDao.removeAllRecipes()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun saveRecipeInfo(recipe: FullRecipeInfo) {
|
override suspend fun saveRecipeInfo(
|
||||||
|
recipe: RecipeEntity,
|
||||||
|
ingredients: List<RecipeIngredientEntity>,
|
||||||
|
instructions: List<RecipeInstructionEntity>
|
||||||
|
) {
|
||||||
logger.v { "saveRecipeInfo() called with: recipe = $recipe" }
|
logger.v { "saveRecipeInfo() called with: recipe = $recipe" }
|
||||||
db.withTransaction {
|
db.withTransaction {
|
||||||
recipeDao.insertRecipe(recipe.toRecipeEntity())
|
recipeDao.insertRecipe(recipe)
|
||||||
|
|
||||||
recipeDao.deleteRecipeIngredients(recipe.remoteId)
|
recipeDao.deleteRecipeIngredients(recipe.remoteId)
|
||||||
val ingredients = recipe.recipeIngredients.map {
|
|
||||||
it.toRecipeIngredientEntity(recipe.remoteId)
|
|
||||||
}
|
|
||||||
recipeDao.insertRecipeIngredients(ingredients)
|
recipeDao.insertRecipeIngredients(ingredients)
|
||||||
|
|
||||||
recipeDao.deleteRecipeInstructions(recipe.remoteId)
|
recipeDao.deleteRecipeInstructions(recipe.remoteId)
|
||||||
val instructions = recipe.recipeInstructions.map {
|
|
||||||
it.toRecipeInstructionEntity(recipe.remoteId)
|
|
||||||
}
|
|
||||||
recipeDao.insertRecipeInstructions(instructions)
|
recipeDao.insertRecipeInstructions(instructions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun queryRecipeInfo(recipeId: String): FullRecipeEntity? {
|
override suspend fun queryRecipeInfo(recipeId: String): RecipeWithSummaryAndIngredientsAndInstructions? {
|
||||||
logger.v { "queryRecipeInfo() called with: recipeId = $recipeId" }
|
logger.v { "queryRecipeInfo() called with: recipeId = $recipeId" }
|
||||||
val fullRecipeInfo = recipeDao.queryFullRecipeInfo(recipeId)
|
val fullRecipeInfo = recipeDao.queryFullRecipeInfo(recipeId)
|
||||||
logger.v { "queryRecipeInfo() returned: $fullRecipeInfo" }
|
logger.v { "queryRecipeInfo() returned: $fullRecipeInfo" }
|
||||||
@@ -6,7 +6,7 @@ import androidx.room.PrimaryKey
|
|||||||
|
|
||||||
@Entity(tableName = "recipe")
|
@Entity(tableName = "recipe")
|
||||||
data class RecipeEntity(
|
data class RecipeEntity(
|
||||||
@PrimaryKey @ColumnInfo(name = "remote_id") val remoteId: String,
|
@PrimaryKey @ColumnInfo(name = "recipe_id") val remoteId: String,
|
||||||
@ColumnInfo(name = "recipe_yield") val recipeYield: String,
|
@ColumnInfo(name = "recipe_yield") val recipeYield: String,
|
||||||
@ColumnInfo(name = "disable_amounts", defaultValue = "true") val disableAmounts: Boolean,
|
@ColumnInfo(name = "recipe_disable_amounts", defaultValue = "true") val disableAmounts: Boolean,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -2,17 +2,28 @@ package gq.kirmanak.mealient.database.recipe.entity
|
|||||||
|
|
||||||
import androidx.room.ColumnInfo
|
import androidx.room.ColumnInfo
|
||||||
import androidx.room.Entity
|
import androidx.room.Entity
|
||||||
|
import androidx.room.ForeignKey
|
||||||
import androidx.room.PrimaryKey
|
import androidx.room.PrimaryKey
|
||||||
|
|
||||||
@Entity(tableName = "recipe_ingredient")
|
@Entity(
|
||||||
|
tableName = "recipe_ingredient",
|
||||||
|
foreignKeys = [
|
||||||
|
ForeignKey(
|
||||||
|
entity = RecipeEntity::class,
|
||||||
|
parentColumns = ["recipe_id"],
|
||||||
|
childColumns = ["recipe_id"],
|
||||||
|
onDelete = ForeignKey.CASCADE
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
data class RecipeIngredientEntity(
|
data class RecipeIngredientEntity(
|
||||||
@PrimaryKey(autoGenerate = true) @ColumnInfo(name = "local_id") val localId: Long = 0,
|
@PrimaryKey(autoGenerate = true) @ColumnInfo(name = "recipe_ingredient_local_id") val localId: Long = 0,
|
||||||
@ColumnInfo(name = "recipe_id") val recipeId: String,
|
@ColumnInfo(name = "recipe_id", index = true) val recipeId: String,
|
||||||
@ColumnInfo(name = "note") val note: String,
|
@ColumnInfo(name = "recipe_ingredient_note") val note: String,
|
||||||
@ColumnInfo(name = "food") val food: String?,
|
@ColumnInfo(name = "recipe_ingredient_food") val food: String?,
|
||||||
@ColumnInfo(name = "unit") val unit: String?,
|
@ColumnInfo(name = "recipe_ingredient_unit") val unit: String?,
|
||||||
@ColumnInfo(name = "quantity") val quantity: Double?,
|
@ColumnInfo(name = "recipe_ingredient_quantity") val quantity: Double?,
|
||||||
@ColumnInfo(name = "title") val title: String?,
|
@ColumnInfo(name = "recipe_ingredient_title") val title: String?,
|
||||||
) {
|
) {
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (this === other) return true
|
if (this === other) return true
|
||||||
|
|||||||
@@ -2,13 +2,24 @@ package gq.kirmanak.mealient.database.recipe.entity
|
|||||||
|
|
||||||
import androidx.room.ColumnInfo
|
import androidx.room.ColumnInfo
|
||||||
import androidx.room.Entity
|
import androidx.room.Entity
|
||||||
|
import androidx.room.ForeignKey
|
||||||
import androidx.room.PrimaryKey
|
import androidx.room.PrimaryKey
|
||||||
|
|
||||||
@Entity(tableName = "recipe_instruction")
|
@Entity(
|
||||||
|
tableName = "recipe_instruction",
|
||||||
|
foreignKeys = [
|
||||||
|
ForeignKey(
|
||||||
|
entity = RecipeEntity::class,
|
||||||
|
parentColumns = ["recipe_id"],
|
||||||
|
childColumns = ["recipe_id"],
|
||||||
|
onDelete = ForeignKey.CASCADE
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
data class RecipeInstructionEntity(
|
data class RecipeInstructionEntity(
|
||||||
@PrimaryKey(autoGenerate = true) @ColumnInfo(name = "local_id") val localId: Long = 0,
|
@PrimaryKey(autoGenerate = true) @ColumnInfo(name = "recipe_instruction_local_id") val localId: Long = 0,
|
||||||
@ColumnInfo(name = "recipe_id") val recipeId: String,
|
@ColumnInfo(name = "recipe_id", index = true) val recipeId: String,
|
||||||
@ColumnInfo(name = "text") val text: String,
|
@ColumnInfo(name = "recipe_instruction_text") val text: String,
|
||||||
) {
|
) {
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (this === other) return true
|
if (this === other) return true
|
||||||
|
|||||||
@@ -8,12 +8,15 @@ import kotlinx.datetime.LocalDateTime
|
|||||||
|
|
||||||
@Entity(tableName = "recipe_summaries")
|
@Entity(tableName = "recipe_summaries")
|
||||||
data class RecipeSummaryEntity(
|
data class RecipeSummaryEntity(
|
||||||
@PrimaryKey @ColumnInfo(name = "remote_id") val remoteId: String,
|
@PrimaryKey @ColumnInfo(name = "recipe_id") val remoteId: String,
|
||||||
@ColumnInfo(name = "name") val name: String,
|
@ColumnInfo(name = "recipe_summaries_name") val name: String,
|
||||||
@ColumnInfo(name = "slug") val slug: String,
|
@ColumnInfo(name = "recipe_summaries_slug") val slug: String,
|
||||||
@ColumnInfo(name = "description") val description: String,
|
@ColumnInfo(name = "recipe_summaries_description") val description: String,
|
||||||
@ColumnInfo(name = "date_added") val dateAdded: LocalDate,
|
@ColumnInfo(name = "recipe_summaries_date_added") val dateAdded: LocalDate,
|
||||||
@ColumnInfo(name = "date_updated") val dateUpdated: LocalDateTime,
|
@ColumnInfo(name = "recipe_summaries_date_updated") val dateUpdated: LocalDateTime,
|
||||||
@ColumnInfo(name = "image_id") val imageId: String?,
|
@ColumnInfo(name = "recipe_summaries_image_id") val imageId: String?,
|
||||||
@ColumnInfo(name = "is_favorite", defaultValue = "false") val isFavorite: Boolean,
|
@ColumnInfo(
|
||||||
|
name = "recipe_summaries_is_favorite",
|
||||||
|
defaultValue = "false"
|
||||||
|
) val isFavorite: Boolean,
|
||||||
)
|
)
|
||||||
@@ -3,20 +3,20 @@ package gq.kirmanak.mealient.database.recipe.entity
|
|||||||
import androidx.room.Embedded
|
import androidx.room.Embedded
|
||||||
import androidx.room.Relation
|
import androidx.room.Relation
|
||||||
|
|
||||||
data class FullRecipeEntity(
|
data class RecipeWithSummaryAndIngredientsAndInstructions(
|
||||||
@Embedded val recipeEntity: RecipeEntity,
|
@Embedded val recipeEntity: RecipeEntity,
|
||||||
@Relation(
|
@Relation(
|
||||||
parentColumn = "remote_id",
|
parentColumn = "recipe_id",
|
||||||
entityColumn = "remote_id"
|
entityColumn = "recipe_id"
|
||||||
)
|
)
|
||||||
val recipeSummaryEntity: RecipeSummaryEntity,
|
val recipeSummaryEntity: RecipeSummaryEntity,
|
||||||
@Relation(
|
@Relation(
|
||||||
parentColumn = "remote_id",
|
parentColumn = "recipe_id",
|
||||||
entityColumn = "recipe_id"
|
entityColumn = "recipe_id"
|
||||||
)
|
)
|
||||||
val recipeIngredients: List<RecipeIngredientEntity>,
|
val recipeIngredients: List<RecipeIngredientEntity>,
|
||||||
@Relation(
|
@Relation(
|
||||||
parentColumn = "remote_id",
|
parentColumn = "recipe_id",
|
||||||
entityColumn = "recipe_id"
|
entityColumn = "recipe_id"
|
||||||
)
|
)
|
||||||
val recipeInstructions: List<RecipeInstructionEntity>,
|
val recipeInstructions: List<RecipeInstructionEntity>,
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
package gq.kirmanak.mealient.database
|
||||||
|
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import dagger.hilt.android.testing.HiltAndroidTest
|
||||||
|
import gq.kirmanak.mealient.database.recipe.RecipeDao
|
||||||
|
import gq.kirmanak.mealient.database.recipe.RecipeStorageImpl
|
||||||
|
import gq.kirmanak.mealient.test.HiltRobolectricTest
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import org.junit.Test
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@HiltAndroidTest
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
internal class RecipeStorageImplTest : HiltRobolectricTest() {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var subject: RecipeStorageImpl
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var recipeDao: RecipeDao
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `when saveRecipes then saves recipes`() = runTest {
|
||||||
|
subject.saveRecipes(TEST_RECIPE_SUMMARY_ENTITIES)
|
||||||
|
val actualTags = recipeDao.queryAllRecipes()
|
||||||
|
assertThat(actualTags).containsExactly(
|
||||||
|
CAKE_RECIPE_SUMMARY_ENTITY,
|
||||||
|
PORRIDGE_RECIPE_SUMMARY_ENTITY
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `when refreshAll then old recipes aren't preserved`() = runTest {
|
||||||
|
subject.saveRecipes(TEST_RECIPE_SUMMARY_ENTITIES)
|
||||||
|
subject.refreshAll(listOf(CAKE_RECIPE_SUMMARY_ENTITY))
|
||||||
|
val actual = recipeDao.queryAllRecipes()
|
||||||
|
assertThat(actual).containsExactly(CAKE_RECIPE_SUMMARY_ENTITY)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `when clearAllLocalData then recipes aren't preserved`() = runTest {
|
||||||
|
subject.saveRecipes(TEST_RECIPE_SUMMARY_ENTITIES)
|
||||||
|
subject.clearAllLocalData()
|
||||||
|
val actual = recipeDao.queryAllRecipes()
|
||||||
|
assertThat(actual).isEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `when saveRecipeInfo then saves recipe info`() = runTest {
|
||||||
|
subject.saveRecipes(listOf(CAKE_RECIPE_SUMMARY_ENTITY))
|
||||||
|
subject.saveRecipeInfo(
|
||||||
|
CAKE_RECIPE_ENTITY,
|
||||||
|
listOf(CAKE_SUGAR_RECIPE_INGREDIENT_ENTITY, CAKE_BREAD_RECIPE_INGREDIENT_ENTITY),
|
||||||
|
listOf(MIX_CAKE_RECIPE_INSTRUCTION_ENTITY, BAKE_CAKE_RECIPE_INSTRUCTION_ENTITY)
|
||||||
|
)
|
||||||
|
val actual = recipeDao.queryFullRecipeInfo("1")
|
||||||
|
assertThat(actual).isEqualTo(FULL_CAKE_INFO_ENTITY)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `when saveRecipeInfo with two then saves second`() = runTest {
|
||||||
|
subject.saveRecipes(TEST_RECIPE_SUMMARY_ENTITIES)
|
||||||
|
subject.saveRecipeInfo(
|
||||||
|
CAKE_RECIPE_ENTITY,
|
||||||
|
listOf(CAKE_SUGAR_RECIPE_INGREDIENT_ENTITY, CAKE_BREAD_RECIPE_INGREDIENT_ENTITY),
|
||||||
|
listOf(MIX_CAKE_RECIPE_INSTRUCTION_ENTITY, BAKE_CAKE_RECIPE_INSTRUCTION_ENTITY),
|
||||||
|
)
|
||||||
|
subject.saveRecipeInfo(
|
||||||
|
PORRIDGE_RECIPE_ENTITY_FULL,
|
||||||
|
listOf(PORRIDGE_SUGAR_RECIPE_INGREDIENT_ENTITY, PORRIDGE_MILK_RECIPE_INGREDIENT_ENTITY),
|
||||||
|
listOf(PORRIDGE_MIX_RECIPE_INSTRUCTION_ENTITY, PORRIDGE_BOIL_RECIPE_INSTRUCTION_ENTITY),
|
||||||
|
)
|
||||||
|
val actual = recipeDao.queryFullRecipeInfo("2")
|
||||||
|
assertThat(actual).isEqualTo(FULL_PORRIDGE_INFO_ENTITY)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `when saveRecipeInfo twice then overwrites ingredients`() = runTest {
|
||||||
|
subject.saveRecipes(listOf(CAKE_RECIPE_SUMMARY_ENTITY))
|
||||||
|
subject.saveRecipeInfo(
|
||||||
|
CAKE_RECIPE_ENTITY,
|
||||||
|
listOf(CAKE_SUGAR_RECIPE_INGREDIENT_ENTITY, CAKE_BREAD_RECIPE_INGREDIENT_ENTITY),
|
||||||
|
listOf(MIX_CAKE_RECIPE_INSTRUCTION_ENTITY, BAKE_CAKE_RECIPE_INSTRUCTION_ENTITY),
|
||||||
|
)
|
||||||
|
subject.saveRecipeInfo(
|
||||||
|
CAKE_RECIPE_ENTITY,
|
||||||
|
listOf(CAKE_BREAD_RECIPE_INGREDIENT_ENTITY),
|
||||||
|
listOf(MIX_CAKE_RECIPE_INSTRUCTION_ENTITY, BAKE_CAKE_RECIPE_INSTRUCTION_ENTITY),
|
||||||
|
)
|
||||||
|
val actual = recipeDao.queryFullRecipeInfo("1")?.recipeIngredients
|
||||||
|
val expected = listOf(CAKE_BREAD_RECIPE_INGREDIENT_ENTITY.copy(localId = 3))
|
||||||
|
assertThat(actual).isEqualTo(expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `when saveRecipeInfo twice then overwrites instructions`() = runTest {
|
||||||
|
subject.saveRecipes(listOf(CAKE_RECIPE_SUMMARY_ENTITY))
|
||||||
|
subject.saveRecipeInfo(
|
||||||
|
CAKE_RECIPE_ENTITY,
|
||||||
|
listOf(CAKE_SUGAR_RECIPE_INGREDIENT_ENTITY, CAKE_BREAD_RECIPE_INGREDIENT_ENTITY),
|
||||||
|
listOf(MIX_CAKE_RECIPE_INSTRUCTION_ENTITY, BAKE_CAKE_RECIPE_INSTRUCTION_ENTITY),
|
||||||
|
)
|
||||||
|
subject.saveRecipeInfo(
|
||||||
|
CAKE_RECIPE_ENTITY,
|
||||||
|
listOf(CAKE_SUGAR_RECIPE_INGREDIENT_ENTITY, CAKE_BREAD_RECIPE_INGREDIENT_ENTITY),
|
||||||
|
listOf(MIX_CAKE_RECIPE_INSTRUCTION_ENTITY),
|
||||||
|
)
|
||||||
|
val actual = recipeDao.queryFullRecipeInfo("1")?.recipeInstructions
|
||||||
|
val expected = listOf(MIX_CAKE_RECIPE_INSTRUCTION_ENTITY.copy(localId = 3))
|
||||||
|
assertThat(actual).isEqualTo(expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
1
database_test/.gitignore
vendored
Normal file
1
database_test/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/build
|
||||||
11
database_test/build.gradle.kts
Normal file
11
database_test/build.gradle.kts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
plugins {
|
||||||
|
id("gq.kirmanak.mealient.library")
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
namespace = "gq.kirmanak.mealient.database_test"
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(project(":database"))
|
||||||
|
}
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
package gq.kirmanak.mealient.database
|
||||||
|
|
||||||
|
import gq.kirmanak.mealient.database.recipe.entity.RecipeEntity
|
||||||
|
import gq.kirmanak.mealient.database.recipe.entity.RecipeIngredientEntity
|
||||||
|
import gq.kirmanak.mealient.database.recipe.entity.RecipeInstructionEntity
|
||||||
|
import gq.kirmanak.mealient.database.recipe.entity.RecipeSummaryEntity
|
||||||
|
import gq.kirmanak.mealient.database.recipe.entity.RecipeWithSummaryAndIngredientsAndInstructions
|
||||||
|
import kotlinx.datetime.LocalDate
|
||||||
|
import kotlinx.datetime.LocalDateTime
|
||||||
|
|
||||||
|
val CAKE_RECIPE_SUMMARY_ENTITY = RecipeSummaryEntity(
|
||||||
|
remoteId = "1",
|
||||||
|
name = "Cake",
|
||||||
|
slug = "cake",
|
||||||
|
description = "A tasty cake",
|
||||||
|
dateAdded = LocalDate.parse("2021-11-13"),
|
||||||
|
dateUpdated = LocalDateTime.parse("2021-11-13T15:30:13"),
|
||||||
|
imageId = "cake",
|
||||||
|
isFavorite = false,
|
||||||
|
)
|
||||||
|
|
||||||
|
val PORRIDGE_RECIPE_SUMMARY_ENTITY = RecipeSummaryEntity(
|
||||||
|
remoteId = "2",
|
||||||
|
name = "Porridge",
|
||||||
|
slug = "porridge",
|
||||||
|
description = "A tasty porridge",
|
||||||
|
dateAdded = LocalDate.parse("2021-11-12"),
|
||||||
|
dateUpdated = LocalDateTime.parse("2021-10-13T17:35:23"),
|
||||||
|
imageId = "porridge",
|
||||||
|
isFavorite = false,
|
||||||
|
)
|
||||||
|
|
||||||
|
val TEST_RECIPE_SUMMARY_ENTITIES =
|
||||||
|
listOf(CAKE_RECIPE_SUMMARY_ENTITY, PORRIDGE_RECIPE_SUMMARY_ENTITY)
|
||||||
|
|
||||||
|
val MIX_CAKE_RECIPE_INSTRUCTION_ENTITY = RecipeInstructionEntity(
|
||||||
|
recipeId = "1",
|
||||||
|
text = "Mix the ingredients",
|
||||||
|
)
|
||||||
|
|
||||||
|
val BAKE_CAKE_RECIPE_INSTRUCTION_ENTITY = RecipeInstructionEntity(
|
||||||
|
recipeId = "1",
|
||||||
|
text = "Bake the ingredients",
|
||||||
|
)
|
||||||
|
|
||||||
|
val CAKE_RECIPE_ENTITY = RecipeEntity(
|
||||||
|
remoteId = "1",
|
||||||
|
recipeYield = "4 servings",
|
||||||
|
disableAmounts = true,
|
||||||
|
)
|
||||||
|
|
||||||
|
val CAKE_SUGAR_RECIPE_INGREDIENT_ENTITY = RecipeIngredientEntity(
|
||||||
|
recipeId = "1",
|
||||||
|
note = "2 oz of white sugar",
|
||||||
|
quantity = 1.0,
|
||||||
|
unit = null,
|
||||||
|
food = null,
|
||||||
|
title = null,
|
||||||
|
)
|
||||||
|
|
||||||
|
val CAKE_BREAD_RECIPE_INGREDIENT_ENTITY = RecipeIngredientEntity(
|
||||||
|
recipeId = "1",
|
||||||
|
note = "2 oz of white bread",
|
||||||
|
quantity = 1.0,
|
||||||
|
unit = null,
|
||||||
|
food = null,
|
||||||
|
title = null,
|
||||||
|
)
|
||||||
|
|
||||||
|
val FULL_CAKE_INFO_ENTITY = RecipeWithSummaryAndIngredientsAndInstructions(
|
||||||
|
recipeEntity = CAKE_RECIPE_ENTITY,
|
||||||
|
recipeSummaryEntity = CAKE_RECIPE_SUMMARY_ENTITY,
|
||||||
|
recipeIngredients = listOf(
|
||||||
|
CAKE_SUGAR_RECIPE_INGREDIENT_ENTITY,
|
||||||
|
CAKE_BREAD_RECIPE_INGREDIENT_ENTITY,
|
||||||
|
),
|
||||||
|
recipeInstructions = listOf(
|
||||||
|
MIX_CAKE_RECIPE_INSTRUCTION_ENTITY,
|
||||||
|
BAKE_CAKE_RECIPE_INSTRUCTION_ENTITY,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
val PORRIDGE_RECIPE_ENTITY_FULL = RecipeEntity(
|
||||||
|
remoteId = "2",
|
||||||
|
recipeYield = "3 servings",
|
||||||
|
disableAmounts = true,
|
||||||
|
)
|
||||||
|
|
||||||
|
val PORRIDGE_MILK_RECIPE_INGREDIENT_ENTITY = RecipeIngredientEntity(
|
||||||
|
recipeId = "2",
|
||||||
|
note = "2 oz of white milk",
|
||||||
|
quantity = 1.0,
|
||||||
|
unit = null,
|
||||||
|
food = null,
|
||||||
|
title = null,
|
||||||
|
)
|
||||||
|
|
||||||
|
val PORRIDGE_SUGAR_RECIPE_INGREDIENT_ENTITY = RecipeIngredientEntity(
|
||||||
|
recipeId = "2",
|
||||||
|
note = "2 oz of white sugar",
|
||||||
|
quantity = 1.0,
|
||||||
|
unit = null,
|
||||||
|
food = null,
|
||||||
|
title = null,
|
||||||
|
)
|
||||||
|
|
||||||
|
val PORRIDGE_MIX_RECIPE_INSTRUCTION_ENTITY = RecipeInstructionEntity(
|
||||||
|
recipeId = "2",
|
||||||
|
text = "Mix the ingredients"
|
||||||
|
)
|
||||||
|
|
||||||
|
val PORRIDGE_BOIL_RECIPE_INSTRUCTION_ENTITY = RecipeInstructionEntity(
|
||||||
|
recipeId = "2",
|
||||||
|
text = "Boil the ingredients"
|
||||||
|
)
|
||||||
|
|
||||||
|
val FULL_PORRIDGE_INFO_ENTITY = RecipeWithSummaryAndIngredientsAndInstructions(
|
||||||
|
recipeEntity = PORRIDGE_RECIPE_ENTITY_FULL,
|
||||||
|
recipeSummaryEntity = PORRIDGE_RECIPE_SUMMARY_ENTITY,
|
||||||
|
recipeIngredients = listOf(
|
||||||
|
PORRIDGE_SUGAR_RECIPE_INGREDIENT_ENTITY,
|
||||||
|
PORRIDGE_MILK_RECIPE_INGREDIENT_ENTITY,
|
||||||
|
),
|
||||||
|
recipeInstructions = listOf(
|
||||||
|
PORRIDGE_MIX_RECIPE_INSTRUCTION_ENTITY,
|
||||||
|
PORRIDGE_BOIL_RECIPE_INSTRUCTION_ENTITY,
|
||||||
|
)
|
||||||
|
)
|
||||||
@@ -21,7 +21,7 @@ dependencies {
|
|||||||
kaptTest(libs.google.dagger.hiltAndroidCompiler)
|
kaptTest(libs.google.dagger.hiltAndroidCompiler)
|
||||||
testImplementation(libs.google.dagger.hiltAndroidTesting)
|
testImplementation(libs.google.dagger.hiltAndroidTesting)
|
||||||
|
|
||||||
implementation(libs.jetbrains.kotlinx.datetime)
|
api(libs.jetbrains.kotlinx.datetime)
|
||||||
|
|
||||||
implementation(libs.jetbrains.kotlinx.serialization)
|
implementation(libs.jetbrains.kotlinx.serialization)
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package gq.kirmanak.mealient.data.add
|
package gq.kirmanak.mealient.datasource.models
|
||||||
|
|
||||||
data class AddRecipeInfo(
|
data class AddRecipeInfo(
|
||||||
val name: String,
|
val name: String,
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package gq.kirmanak.mealient.data.recipes.network
|
package gq.kirmanak.mealient.datasource.models
|
||||||
|
|
||||||
data class FullRecipeInfo(
|
data class FullRecipeInfo(
|
||||||
val remoteId: String,
|
val remoteId: String,
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package gq.kirmanak.mealient.datasource.models
|
||||||
|
|
||||||
|
data class FullShoppingListInfo(
|
||||||
|
val id: String,
|
||||||
|
val name: String,
|
||||||
|
val items: List<ShoppingListItemInfo>,
|
||||||
|
)
|
||||||
|
|
||||||
|
data class ShoppingListItemInfo(
|
||||||
|
val shoppingListId: String,
|
||||||
|
val id: String,
|
||||||
|
val checked: Boolean,
|
||||||
|
val position: Int,
|
||||||
|
val isFood: Boolean,
|
||||||
|
val note: String,
|
||||||
|
val quantity: Double,
|
||||||
|
val unit: String,
|
||||||
|
val food: String,
|
||||||
|
val recipeReferences: List<ShoppingListItemRecipeReferenceInfo>,
|
||||||
|
)
|
||||||
|
|
||||||
|
data class ShoppingListItemRecipeReferenceInfo(
|
||||||
|
val recipeId: String,
|
||||||
|
val recipeQuantity: Double,
|
||||||
|
val id: String,
|
||||||
|
val shoppingListId: String,
|
||||||
|
val recipe: FullRecipeInfo,
|
||||||
|
)
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package gq.kirmanak.mealient.data.share
|
package gq.kirmanak.mealient.datasource.models
|
||||||
|
|
||||||
data class ParseRecipeURLInfo(
|
data class ParseRecipeURLInfo(
|
||||||
val url: String,
|
val url: String,
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package gq.kirmanak.mealient.data.recipes.network
|
package gq.kirmanak.mealient.datasource.models
|
||||||
|
|
||||||
import kotlinx.datetime.LocalDate
|
import kotlinx.datetime.LocalDate
|
||||||
import kotlinx.datetime.LocalDateTime
|
import kotlinx.datetime.LocalDateTime
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package gq.kirmanak.mealient.datasource.models
|
||||||
|
|
||||||
|
data class ShoppingListsInfo(
|
||||||
|
val page: Int,
|
||||||
|
val perPage: Int,
|
||||||
|
val totalPages: Int,
|
||||||
|
val totalItems: Int,
|
||||||
|
val items: List<ShoppingListInfo>,
|
||||||
|
)
|
||||||
|
|
||||||
|
data class ShoppingListInfo(
|
||||||
|
val name: String,
|
||||||
|
val id: String,
|
||||||
|
)
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package gq.kirmanak.mealient.data.baseurl
|
package gq.kirmanak.mealient.datasource.models
|
||||||
|
|
||||||
data class VersionInfo(
|
data class VersionInfo(
|
||||||
val version: String,
|
val version: String,
|
||||||
@@ -5,6 +5,8 @@ import gq.kirmanak.mealient.datasource.v1.models.CreateApiTokenResponseV1
|
|||||||
import gq.kirmanak.mealient.datasource.v1.models.CreateRecipeRequestV1
|
import gq.kirmanak.mealient.datasource.v1.models.CreateRecipeRequestV1
|
||||||
import gq.kirmanak.mealient.datasource.v1.models.GetRecipeResponseV1
|
import gq.kirmanak.mealient.datasource.v1.models.GetRecipeResponseV1
|
||||||
import gq.kirmanak.mealient.datasource.v1.models.GetRecipeSummaryResponseV1
|
import gq.kirmanak.mealient.datasource.v1.models.GetRecipeSummaryResponseV1
|
||||||
|
import gq.kirmanak.mealient.datasource.v1.models.GetShoppingListResponseV1
|
||||||
|
import gq.kirmanak.mealient.datasource.v1.models.GetShoppingListsResponseV1
|
||||||
import gq.kirmanak.mealient.datasource.v1.models.GetUserInfoResponseV1
|
import gq.kirmanak.mealient.datasource.v1.models.GetUserInfoResponseV1
|
||||||
import gq.kirmanak.mealient.datasource.v1.models.ParseRecipeURLRequestV1
|
import gq.kirmanak.mealient.datasource.v1.models.ParseRecipeURLRequestV1
|
||||||
import gq.kirmanak.mealient.datasource.v1.models.UpdateRecipeRequestV1
|
import gq.kirmanak.mealient.datasource.v1.models.UpdateRecipeRequestV1
|
||||||
@@ -54,5 +56,12 @@ interface MealieDataSourceV1 {
|
|||||||
suspend fun removeFavoriteRecipe(userId: String, recipeSlug: String)
|
suspend fun removeFavoriteRecipe(userId: String, recipeSlug: String)
|
||||||
|
|
||||||
suspend fun addFavoriteRecipe(userId: String, recipeSlug: String)
|
suspend fun addFavoriteRecipe(userId: String, recipeSlug: String)
|
||||||
|
|
||||||
suspend fun deleteRecipe(slug: String)
|
suspend fun deleteRecipe(slug: String)
|
||||||
|
|
||||||
|
suspend fun getShoppingLists(page: Int, perPage: Int): GetShoppingListsResponseV1
|
||||||
|
|
||||||
|
suspend fun getShoppingList(id: String): GetShoppingListResponseV1
|
||||||
|
|
||||||
|
suspend fun updateIsShoppingListItemChecked(id: String, isChecked: Boolean)
|
||||||
}
|
}
|
||||||
@@ -9,12 +9,20 @@ import gq.kirmanak.mealient.datasource.v1.models.CreateRecipeRequestV1
|
|||||||
import gq.kirmanak.mealient.datasource.v1.models.ErrorDetailV1
|
import gq.kirmanak.mealient.datasource.v1.models.ErrorDetailV1
|
||||||
import gq.kirmanak.mealient.datasource.v1.models.GetRecipeResponseV1
|
import gq.kirmanak.mealient.datasource.v1.models.GetRecipeResponseV1
|
||||||
import gq.kirmanak.mealient.datasource.v1.models.GetRecipeSummaryResponseV1
|
import gq.kirmanak.mealient.datasource.v1.models.GetRecipeSummaryResponseV1
|
||||||
|
import gq.kirmanak.mealient.datasource.v1.models.GetShoppingListResponseV1
|
||||||
|
import gq.kirmanak.mealient.datasource.v1.models.GetShoppingListsResponseV1
|
||||||
import gq.kirmanak.mealient.datasource.v1.models.GetUserInfoResponseV1
|
import gq.kirmanak.mealient.datasource.v1.models.GetUserInfoResponseV1
|
||||||
import gq.kirmanak.mealient.datasource.v1.models.ParseRecipeURLRequestV1
|
import gq.kirmanak.mealient.datasource.v1.models.ParseRecipeURLRequestV1
|
||||||
import gq.kirmanak.mealient.datasource.v1.models.UpdateRecipeRequestV1
|
import gq.kirmanak.mealient.datasource.v1.models.UpdateRecipeRequestV1
|
||||||
import gq.kirmanak.mealient.datasource.v1.models.VersionResponseV1
|
import gq.kirmanak.mealient.datasource.v1.models.VersionResponseV1
|
||||||
import kotlinx.serialization.SerializationException
|
import kotlinx.serialization.SerializationException
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
|
import kotlinx.serialization.json.JsonElement
|
||||||
|
import kotlinx.serialization.json.JsonObject
|
||||||
|
import kotlinx.serialization.json.JsonPrimitive
|
||||||
|
import kotlinx.serialization.json.boolean
|
||||||
|
import kotlinx.serialization.json.jsonObject
|
||||||
|
import kotlinx.serialization.json.jsonPrimitive
|
||||||
import retrofit2.HttpException
|
import retrofit2.HttpException
|
||||||
import java.net.ConnectException
|
import java.net.ConnectException
|
||||||
import java.net.SocketTimeoutException
|
import java.net.SocketTimeoutException
|
||||||
@@ -134,5 +142,52 @@ class MealieDataSourceV1Impl @Inject constructor(
|
|||||||
logMethod = { "deleteRecipe" },
|
logMethod = { "deleteRecipe" },
|
||||||
logParameters = { "slug = $slug" }
|
logParameters = { "slug = $slug" }
|
||||||
)
|
)
|
||||||
}
|
|
||||||
|
|
||||||
|
override suspend fun getShoppingLists(
|
||||||
|
page: Int,
|
||||||
|
perPage: Int,
|
||||||
|
): GetShoppingListsResponseV1 = networkRequestWrapper.makeCallAndHandleUnauthorized(
|
||||||
|
block = { service.getShoppingLists(page, perPage) },
|
||||||
|
logMethod = { "getShoppingLists" },
|
||||||
|
logParameters = { "page = $page, perPage = $perPage" }
|
||||||
|
)
|
||||||
|
|
||||||
|
override suspend fun getShoppingList(
|
||||||
|
id: String
|
||||||
|
): GetShoppingListResponseV1 = networkRequestWrapper.makeCallAndHandleUnauthorized(
|
||||||
|
block = { service.getShoppingList(id) },
|
||||||
|
logMethod = { "getShoppingList" },
|
||||||
|
logParameters = { "id = $id" }
|
||||||
|
)
|
||||||
|
|
||||||
|
private suspend fun getShoppingListItem(
|
||||||
|
id: String,
|
||||||
|
): JsonElement = networkRequestWrapper.makeCallAndHandleUnauthorized(
|
||||||
|
block = { service.getShoppingListItem(id) },
|
||||||
|
logMethod = { "getShoppingListItem" },
|
||||||
|
logParameters = { "id = $id" }
|
||||||
|
)
|
||||||
|
|
||||||
|
private suspend fun updateShoppingListItem(
|
||||||
|
id: String,
|
||||||
|
request: JsonElement,
|
||||||
|
) = networkRequestWrapper.makeCallAndHandleUnauthorized(
|
||||||
|
block = { service.updateShoppingListItem(id, request) },
|
||||||
|
logMethod = { "updateShoppingListItem" },
|
||||||
|
logParameters = { "id = $id, request = $request" }
|
||||||
|
)
|
||||||
|
|
||||||
|
override suspend fun updateIsShoppingListItemChecked(
|
||||||
|
id: String,
|
||||||
|
isChecked: Boolean
|
||||||
|
) {
|
||||||
|
// Has to be done in two steps because the API doesn't support updating the checked state
|
||||||
|
val item = getShoppingListItem(id)
|
||||||
|
val wasChecked = item.jsonObject.getValue("checked").jsonPrimitive.boolean
|
||||||
|
if (wasChecked == isChecked) return
|
||||||
|
val updatedItem = item.jsonObject.toMutableMap().apply {
|
||||||
|
put("checked", JsonPrimitive(isChecked))
|
||||||
|
}
|
||||||
|
updateShoppingListItem(id, JsonObject(updatedItem))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package gq.kirmanak.mealient.datasource.v1
|
package gq.kirmanak.mealient.datasource.v1
|
||||||
|
|
||||||
import gq.kirmanak.mealient.datasource.v1.models.*
|
import gq.kirmanak.mealient.datasource.v1.models.*
|
||||||
|
import kotlinx.serialization.json.JsonElement
|
||||||
import retrofit2.http.*
|
import retrofit2.http.*
|
||||||
|
|
||||||
interface MealieServiceV1 {
|
interface MealieServiceV1 {
|
||||||
@@ -66,4 +67,26 @@ interface MealieServiceV1 {
|
|||||||
suspend fun deleteRecipe(
|
suspend fun deleteRecipe(
|
||||||
@Path("slug") slug: String
|
@Path("slug") slug: String
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@GET("/api/groups/shopping/lists")
|
||||||
|
suspend fun getShoppingLists(
|
||||||
|
@Query("page") page: Int,
|
||||||
|
@Query("perPage") perPage: Int,
|
||||||
|
): GetShoppingListsResponseV1
|
||||||
|
|
||||||
|
@GET("/api/groups/shopping/lists/{id}")
|
||||||
|
suspend fun getShoppingList(
|
||||||
|
@Path("id") id: String,
|
||||||
|
): GetShoppingListResponseV1
|
||||||
|
|
||||||
|
@GET("/api/groups/shopping/items/{id}")
|
||||||
|
suspend fun getShoppingListItem(
|
||||||
|
@Path("id") id: String,
|
||||||
|
): JsonElement
|
||||||
|
|
||||||
|
@PUT("/api/groups/shopping/items/{id}")
|
||||||
|
suspend fun updateShoppingListItem(
|
||||||
|
@Path("id") id: String,
|
||||||
|
@Body request: JsonElement,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package gq.kirmanak.mealient.datasource.v1.models
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class GetRecipeIngredientFoodResponseV1(
|
||||||
|
@SerialName("name") val name: String = "",
|
||||||
|
)
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package gq.kirmanak.mealient.datasource.v1.models
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class GetRecipeIngredientUnitResponseV1(
|
||||||
|
@SerialName("name") val name: String = "",
|
||||||
|
)
|
||||||
@@ -10,7 +10,7 @@ data class GetRecipeResponseV1(
|
|||||||
@SerialName("recipeYield") val recipeYield: String = "",
|
@SerialName("recipeYield") val recipeYield: String = "",
|
||||||
@SerialName("recipeIngredient") val recipeIngredients: List<GetRecipeIngredientResponseV1> = emptyList(),
|
@SerialName("recipeIngredient") val recipeIngredients: List<GetRecipeIngredientResponseV1> = emptyList(),
|
||||||
@SerialName("recipeInstructions") val recipeInstructions: List<GetRecipeInstructionResponseV1> = emptyList(),
|
@SerialName("recipeInstructions") val recipeInstructions: List<GetRecipeInstructionResponseV1> = emptyList(),
|
||||||
@SerialName("settings") val settings: GetRecipeSettingsResponseV1,
|
@SerialName("settings") val settings: GetRecipeSettingsResponseV1? = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@@ -27,16 +27,6 @@ data class GetRecipeIngredientResponseV1(
|
|||||||
@SerialName("title") val title: String?,
|
@SerialName("title") val title: String?,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class GetRecipeIngredientFoodResponseV1(
|
|
||||||
@SerialName("name") val name: String = "",
|
|
||||||
)
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class GetRecipeIngredientUnitResponseV1(
|
|
||||||
@SerialName("name") val name: String = "",
|
|
||||||
)
|
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class GetRecipeInstructionResponseV1(
|
data class GetRecipeInstructionResponseV1(
|
||||||
@SerialName("text") val text: String,
|
@SerialName("text") val text: String,
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package gq.kirmanak.mealient.datasource.v1.models
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class GetShoppingListResponseV1(
|
||||||
|
@SerialName("id") val id: String,
|
||||||
|
@SerialName("groupId") val groupId: String,
|
||||||
|
@SerialName("name") val name: String = "",
|
||||||
|
@SerialName("listItems") val listItems: List<GetShoppingListItemResponseV1> = emptyList(),
|
||||||
|
@SerialName("recipeReferences") val recipeReferences: List<GetShoppingListItemRecipeReferenceFullResponseV1>,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class GetShoppingListItemResponseV1(
|
||||||
|
@SerialName("shoppingListId") val shoppingListId: String,
|
||||||
|
@SerialName("id") val id: String,
|
||||||
|
@SerialName("checked") val checked: Boolean = false,
|
||||||
|
@SerialName("position") val position: Int = 0,
|
||||||
|
@SerialName("isFood") val isFood: Boolean = false,
|
||||||
|
@SerialName("note") val note: String = "",
|
||||||
|
@SerialName("quantity") val quantity: Double = 0.0,
|
||||||
|
@SerialName("unit") val unit: GetRecipeIngredientUnitResponseV1? = null,
|
||||||
|
@SerialName("food") val food: GetRecipeIngredientFoodResponseV1? = null,
|
||||||
|
@SerialName("recipeReferences") val recipeReferences: List<GetShoppingListItemRecipeReferenceResponseV1> = emptyList(),
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class GetShoppingListItemRecipeReferenceResponseV1(
|
||||||
|
@SerialName("recipeId") val recipeId: String,
|
||||||
|
@SerialName("recipeQuantity") val recipeQuantity: Double = 0.0
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class GetShoppingListItemRecipeReferenceFullResponseV1(
|
||||||
|
@SerialName("id") val id: String,
|
||||||
|
@SerialName("shoppingListId") val shoppingListId: String,
|
||||||
|
@SerialName("recipeId") val recipeId: String,
|
||||||
|
@SerialName("recipeQuantity") val recipeQuantity: Double = 0.0,
|
||||||
|
@SerialName("recipe") val recipe: GetRecipeResponseV1,
|
||||||
|
)
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package gq.kirmanak.mealient.datasource.v1.models
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class GetShoppingListsResponseV1(
|
||||||
|
@SerialName("page") val page: Int,
|
||||||
|
@SerialName("per_page") val perPage: Int,
|
||||||
|
@SerialName("total") val total: Int,
|
||||||
|
@SerialName("total_pages") val totalPages: Int,
|
||||||
|
@SerialName("items") val items: List<GetShoppingListsSummaryResponseV1>,
|
||||||
|
)
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package gq.kirmanak.mealient.datasource.v1.models
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class GetShoppingListsSummaryResponseV1(
|
||||||
|
@SerialName("id") val id: String,
|
||||||
|
@SerialName("name") val name: String?,
|
||||||
|
)
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user