Allow viewing recipes on V1
This commit is contained in:
@@ -9,8 +9,10 @@ import gq.kirmanak.mealient.data.recipes.network.RecipeDataSource
|
|||||||
import gq.kirmanak.mealient.datasource.MealieDataSource
|
import gq.kirmanak.mealient.datasource.MealieDataSource
|
||||||
import gq.kirmanak.mealient.datasource.models.AddRecipeRequest
|
import gq.kirmanak.mealient.datasource.models.AddRecipeRequest
|
||||||
import gq.kirmanak.mealient.datasource.models.GetRecipeResponse
|
import gq.kirmanak.mealient.datasource.models.GetRecipeResponse
|
||||||
import gq.kirmanak.mealient.datasource.models.GetRecipeSummaryResponse
|
|
||||||
import gq.kirmanak.mealient.datasource.models.NetworkError
|
import gq.kirmanak.mealient.datasource.models.NetworkError
|
||||||
|
import gq.kirmanak.mealient.datasource.v1.MealieDataSourceV1
|
||||||
|
import gq.kirmanak.mealient.datasource.v1.models.GetRecipeSummaryResponseV1
|
||||||
|
import gq.kirmanak.mealient.extensions.runCatchingExceptCancel
|
||||||
import gq.kirmanak.mealient.extensions.toVersionInfo
|
import gq.kirmanak.mealient.extensions.toVersionInfo
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
@@ -20,28 +22,52 @@ class MealieDataSourceWrapper @Inject constructor(
|
|||||||
private val baseURLStorage: BaseURLStorage,
|
private val baseURLStorage: BaseURLStorage,
|
||||||
private val authRepo: AuthRepo,
|
private val authRepo: AuthRepo,
|
||||||
private val mealieDataSource: MealieDataSource,
|
private val mealieDataSource: MealieDataSource,
|
||||||
|
private val mealieDataSourceV1: MealieDataSourceV1,
|
||||||
) : AddRecipeDataSource, RecipeDataSource, VersionDataSource {
|
) : AddRecipeDataSource, RecipeDataSource, VersionDataSource {
|
||||||
|
|
||||||
override suspend fun addRecipe(recipe: AddRecipeRequest): String =
|
override suspend fun addRecipe(recipe: AddRecipeRequest): String =
|
||||||
withAuthHeader { token -> addRecipe(getUrl(), token, recipe) }
|
withAuthHeader { token -> mealieDataSource.addRecipe(getUrl(), token, recipe) }
|
||||||
|
|
||||||
override suspend fun getVersionInfo(baseUrl: String): VersionInfo =
|
override suspend fun getVersionInfo(baseUrl: String): VersionInfo =
|
||||||
mealieDataSource.getVersionInfo(baseUrl).toVersionInfo()
|
mealieDataSource.getVersionInfo(baseUrl).toVersionInfo()
|
||||||
|
|
||||||
override suspend fun requestRecipes(start: Int, limit: Int): List<GetRecipeSummaryResponse> =
|
override suspend fun requestRecipes(start: Int, limit: Int): List<GetRecipeSummaryResponseV1> =
|
||||||
withAuthHeader { token -> requestRecipes(getUrl(), token, start, limit) }
|
withAuthHeader { token ->
|
||||||
|
runCatchingExceptCancel {
|
||||||
|
mealieDataSource.requestRecipes(getUrl(), token, start, limit).map {
|
||||||
|
GetRecipeSummaryResponseV1(
|
||||||
|
remoteId = it.remoteId.toString(),
|
||||||
|
name = it.name,
|
||||||
|
slug = it.slug,
|
||||||
|
image = it.image,
|
||||||
|
description = it.description,
|
||||||
|
recipeCategories = it.recipeCategories,
|
||||||
|
tags = it.tags,
|
||||||
|
rating = it.rating,
|
||||||
|
dateAdded = it.dateAdded,
|
||||||
|
dateUpdated = it.dateUpdated,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}.getOrElse {
|
||||||
|
if (it is NetworkError.NotMealie) {
|
||||||
|
mealieDataSourceV1.requestRecipes(getUrl(), token, start, limit)
|
||||||
|
} else {
|
||||||
|
throw it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun requestRecipeInfo(slug: String): GetRecipeResponse =
|
override suspend fun requestRecipeInfo(slug: String): GetRecipeResponse =
|
||||||
withAuthHeader { token -> requestRecipeInfo(getUrl(), token, slug) }
|
withAuthHeader { token -> mealieDataSource.requestRecipeInfo(getUrl(), token, slug) }
|
||||||
|
|
||||||
private suspend fun getUrl() = baseURLStorage.requireBaseURL()
|
private suspend fun getUrl() = baseURLStorage.requireBaseURL()
|
||||||
|
|
||||||
private suspend inline fun <T> withAuthHeader(block: MealieDataSource.(String?) -> T): T =
|
private suspend inline fun <T> withAuthHeader(block: (String?) -> T): T =
|
||||||
mealieDataSource.runCatching { block(authRepo.getAuthHeader()) }.getOrElse {
|
runCatching { block(authRepo.getAuthHeader()) }.getOrElse {
|
||||||
if (it is NetworkError.Unauthorized) {
|
if (it is NetworkError.Unauthorized) {
|
||||||
authRepo.invalidateAuthHeader()
|
authRepo.invalidateAuthHeader()
|
||||||
// Trying again with new authentication header
|
// Trying again with new authentication header
|
||||||
mealieDataSource.block(authRepo.getAuthHeader())
|
block(authRepo.getAuthHeader())
|
||||||
} else {
|
} else {
|
||||||
throw it
|
throw it
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,14 +4,14 @@ import androidx.paging.PagingSource
|
|||||||
import gq.kirmanak.mealient.database.recipe.entity.FullRecipeInfo
|
import gq.kirmanak.mealient.database.recipe.entity.FullRecipeInfo
|
||||||
import gq.kirmanak.mealient.database.recipe.entity.RecipeSummaryEntity
|
import gq.kirmanak.mealient.database.recipe.entity.RecipeSummaryEntity
|
||||||
import gq.kirmanak.mealient.datasource.models.GetRecipeResponse
|
import gq.kirmanak.mealient.datasource.models.GetRecipeResponse
|
||||||
import gq.kirmanak.mealient.datasource.models.GetRecipeSummaryResponse
|
import gq.kirmanak.mealient.datasource.v1.models.GetRecipeSummaryResponseV1
|
||||||
|
|
||||||
interface RecipeStorage {
|
interface RecipeStorage {
|
||||||
suspend fun saveRecipes(recipes: List<GetRecipeSummaryResponse>)
|
suspend fun saveRecipes(recipes: List<GetRecipeSummaryResponseV1>)
|
||||||
|
|
||||||
fun queryRecipes(): PagingSource<Int, RecipeSummaryEntity>
|
fun queryRecipes(): PagingSource<Int, RecipeSummaryEntity>
|
||||||
|
|
||||||
suspend fun refreshAll(recipes: List<GetRecipeSummaryResponse>)
|
suspend fun refreshAll(recipes: List<GetRecipeSummaryResponseV1>)
|
||||||
|
|
||||||
suspend fun clearAllLocalData()
|
suspend fun clearAllLocalData()
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import gq.kirmanak.mealient.database.AppDb
|
|||||||
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.*
|
||||||
import gq.kirmanak.mealient.datasource.models.GetRecipeResponse
|
import gq.kirmanak.mealient.datasource.models.GetRecipeResponse
|
||||||
import gq.kirmanak.mealient.datasource.models.GetRecipeSummaryResponse
|
import gq.kirmanak.mealient.datasource.v1.models.GetRecipeSummaryResponseV1
|
||||||
import gq.kirmanak.mealient.extensions.recipeEntity
|
import gq.kirmanak.mealient.extensions.recipeEntity
|
||||||
import gq.kirmanak.mealient.extensions.toRecipeEntity
|
import gq.kirmanak.mealient.extensions.toRecipeEntity
|
||||||
import gq.kirmanak.mealient.extensions.toRecipeIngredientEntity
|
import gq.kirmanak.mealient.extensions.toRecipeIngredientEntity
|
||||||
@@ -23,7 +23,7 @@ class RecipeStorageImpl @Inject constructor(
|
|||||||
private val recipeDao: RecipeDao by lazy { db.recipeDao() }
|
private val recipeDao: RecipeDao by lazy { db.recipeDao() }
|
||||||
|
|
||||||
override suspend fun saveRecipes(
|
override suspend fun saveRecipes(
|
||||||
recipes: List<GetRecipeSummaryResponse>
|
recipes: List<GetRecipeSummaryResponseV1>
|
||||||
) = db.withTransaction {
|
) = db.withTransaction {
|
||||||
logger.v { "saveRecipes() called with $recipes" }
|
logger.v { "saveRecipes() called with $recipes" }
|
||||||
|
|
||||||
@@ -96,7 +96,7 @@ class RecipeStorageImpl @Inject constructor(
|
|||||||
return recipeDao.queryRecipesByPages()
|
return recipeDao.queryRecipesByPages()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun refreshAll(recipes: List<GetRecipeSummaryResponse>) {
|
override suspend fun refreshAll(recipes: List<GetRecipeSummaryResponseV1>) {
|
||||||
logger.v { "refreshAll() called with: recipes = $recipes" }
|
logger.v { "refreshAll() called with: recipes = $recipes" }
|
||||||
db.withTransaction {
|
db.withTransaction {
|
||||||
recipeDao.removeAllRecipes()
|
recipeDao.removeAllRecipes()
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package gq.kirmanak.mealient.data.recipes.network
|
package gq.kirmanak.mealient.data.recipes.network
|
||||||
|
|
||||||
import gq.kirmanak.mealient.datasource.models.GetRecipeResponse
|
import gq.kirmanak.mealient.datasource.models.GetRecipeResponse
|
||||||
import gq.kirmanak.mealient.datasource.models.GetRecipeSummaryResponse
|
import gq.kirmanak.mealient.datasource.v1.models.GetRecipeSummaryResponseV1
|
||||||
|
|
||||||
interface RecipeDataSource {
|
interface RecipeDataSource {
|
||||||
suspend fun requestRecipes(start: Int, limit: Int): List<GetRecipeSummaryResponse>
|
suspend fun requestRecipes(start: Int, limit: Int): List<GetRecipeSummaryResponseV1>
|
||||||
|
|
||||||
suspend fun requestRecipeInfo(slug: String): GetRecipeResponse
|
suspend fun requestRecipeInfo(slug: String): GetRecipeResponse
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,7 @@ import gq.kirmanak.mealient.database.recipe.entity.RecipeIngredientEntity
|
|||||||
import gq.kirmanak.mealient.database.recipe.entity.RecipeInstructionEntity
|
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.datasource.models.*
|
import gq.kirmanak.mealient.datasource.models.*
|
||||||
|
import gq.kirmanak.mealient.datasource.v1.models.GetRecipeSummaryResponseV1
|
||||||
import gq.kirmanak.mealient.datastore.recipe.AddRecipeDraft
|
import gq.kirmanak.mealient.datastore.recipe.AddRecipeDraft
|
||||||
|
|
||||||
fun GetRecipeResponse.toRecipeEntity() = RecipeEntity(
|
fun GetRecipeResponse.toRecipeEntity() = RecipeEntity(
|
||||||
@@ -31,7 +32,7 @@ fun GetRecipeInstructionResponse.toRecipeInstructionEntity(remoteId: String) =
|
|||||||
text = text
|
text = text
|
||||||
)
|
)
|
||||||
|
|
||||||
fun GetRecipeSummaryResponse.recipeEntity() = RecipeSummaryEntity(
|
fun GetRecipeSummaryResponseV1.recipeEntity() = RecipeSummaryEntity(
|
||||||
remoteId = remoteId,
|
remoteId = remoteId,
|
||||||
name = name,
|
name = name,
|
||||||
slug = slug,
|
slug = slug,
|
||||||
|
|||||||
@@ -6,6 +6,9 @@ import dagger.Module
|
|||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
import dagger.hilt.InstallIn
|
import dagger.hilt.InstallIn
|
||||||
import dagger.hilt.components.SingletonComponent
|
import dagger.hilt.components.SingletonComponent
|
||||||
|
import gq.kirmanak.mealient.datasource.v1.MealieDataSourceV1
|
||||||
|
import gq.kirmanak.mealient.datasource.v1.MealieDataSourceV1Impl
|
||||||
|
import gq.kirmanak.mealient.datasource.v1.MealieServiceV1
|
||||||
import kotlinx.serialization.ExperimentalSerializationApi
|
import kotlinx.serialization.ExperimentalSerializationApi
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import okhttp3.MediaType.Companion.toMediaType
|
import okhttp3.MediaType.Companion.toMediaType
|
||||||
@@ -52,6 +55,10 @@ interface DataSourceModule {
|
|||||||
fun provideMealieService(retrofit: Retrofit): MealieService =
|
fun provideMealieService(retrofit: Retrofit): MealieService =
|
||||||
retrofit.create()
|
retrofit.create()
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideMealieServiceV1(retrofit: Retrofit): MealieServiceV1 =
|
||||||
|
retrofit.create()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
@@ -65,4 +72,8 @@ interface DataSourceModule {
|
|||||||
@Binds
|
@Binds
|
||||||
@Singleton
|
@Singleton
|
||||||
fun bindMealieDataSource(mealientDataSourceImpl: MealieDataSourceImpl): MealieDataSource
|
fun bindMealieDataSource(mealientDataSourceImpl: MealieDataSourceImpl): MealieDataSource
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@Singleton
|
||||||
|
fun bindMealieDataSourceV1(mealientDataSourceImpl: MealieDataSourceV1Impl): MealieDataSourceV1
|
||||||
}
|
}
|
||||||
@@ -73,20 +73,7 @@ class MealieDataSourceImpl @Inject constructor(
|
|||||||
logParameters = { "baseUrl = $baseUrl, token = $token, start = $start, limit = $limit" }
|
logParameters = { "baseUrl = $baseUrl, token = $token, start = $start, limit = $limit" }
|
||||||
).getOrElse {
|
).getOrElse {
|
||||||
val code = (it as? HttpException)?.code() ?: throw it
|
val code = (it as? HttpException)?.code() ?: throw it
|
||||||
if (code == 404) requestRecipesV1(baseUrl, token, start, limit) else throw it
|
if (code == 404) throw NetworkError.NotMealie(it) else throw it
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun requestRecipesV1(
|
|
||||||
baseUrl: String, token: String?, start: Int, limit: Int
|
|
||||||
): List<GetRecipeSummaryResponse> {
|
|
||||||
// Imagine start is 30 and limit is 15. It means that we already have page 1 and 2, now we need page 3
|
|
||||||
val perPage = limit
|
|
||||||
val page = start / perPage + 1
|
|
||||||
return makeCall(
|
|
||||||
block = { getRecipeSummaryV1("$baseUrl/api/recipes", token, page, perPage) },
|
|
||||||
logMethod = { "requestRecipesV1" },
|
|
||||||
logParameters = { "baseUrl = $baseUrl, token = $token, start = $start, limit = $limit" }
|
|
||||||
).map { it.items }.getOrThrowUnauthorized()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun requestRecipeInfo(
|
override suspend fun requestRecipeInfo(
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
package gq.kirmanak.mealient.datasource
|
|
||||||
|
|
||||||
import gq.kirmanak.mealient.datasource.models.AddRecipeRequest
|
|
||||||
import gq.kirmanak.mealient.datasource.models.GetRecipeResponse
|
|
||||||
import gq.kirmanak.mealient.datasource.models.GetRecipeSummaryResponse
|
|
||||||
import gq.kirmanak.mealient.datasource.models.VersionResponse
|
|
||||||
|
|
||||||
class MealieDataSourceV1Impl : MealieDataSourceV1 {
|
|
||||||
override suspend fun addRecipe(
|
|
||||||
baseUrl: String,
|
|
||||||
token: String?,
|
|
||||||
recipe: AddRecipeRequest
|
|
||||||
): String {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun authenticate(baseUrl: String, username: String, password: String): String {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun getVersionInfo(baseUrl: String): VersionResponse {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun requestRecipes(
|
|
||||||
baseUrl: String,
|
|
||||||
token: String?,
|
|
||||||
start: Int,
|
|
||||||
limit: Int
|
|
||||||
): List<GetRecipeSummaryResponse> {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun requestRecipeInfo(
|
|
||||||
baseUrl: String,
|
|
||||||
token: String?,
|
|
||||||
slug: String
|
|
||||||
): GetRecipeResponse {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -34,14 +34,6 @@ interface MealieService {
|
|||||||
@Query("limit") limit: Int,
|
@Query("limit") limit: Int,
|
||||||
): List<GetRecipeSummaryResponse>
|
): List<GetRecipeSummaryResponse>
|
||||||
|
|
||||||
@GET
|
|
||||||
suspend fun getRecipeSummaryV1(
|
|
||||||
@Url url: String,
|
|
||||||
@Header(AUTHORIZATION_HEADER_NAME) token: String?,
|
|
||||||
@Query("page") page: Int,
|
|
||||||
@Query("perPage") perPage: Int,
|
|
||||||
): GetRecipesResponseV1
|
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
suspend fun getRecipe(
|
suspend fun getRecipe(
|
||||||
@Url url: String,
|
@Url url: String,
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import kotlinx.serialization.Serializable
|
|||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class GetRecipeSummaryResponse(
|
data class GetRecipeSummaryResponse(
|
||||||
@SerialName("id") val remoteId: String,
|
@SerialName("id") val remoteId: Int,
|
||||||
@SerialName("name") val name: String,
|
@SerialName("name") val name: String,
|
||||||
@SerialName("slug") val slug: String,
|
@SerialName("slug") val slug: String,
|
||||||
@SerialName("image") val image: String?,
|
@SerialName("image") val image: String?,
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
package gq.kirmanak.mealient.datasource
|
package gq.kirmanak.mealient.datasource.v1
|
||||||
|
|
||||||
import gq.kirmanak.mealient.datasource.models.AddRecipeRequest
|
import gq.kirmanak.mealient.datasource.models.AddRecipeRequest
|
||||||
import gq.kirmanak.mealient.datasource.models.GetRecipeResponse
|
import gq.kirmanak.mealient.datasource.models.GetRecipeResponse
|
||||||
import gq.kirmanak.mealient.datasource.models.GetRecipeSummaryResponse
|
|
||||||
import gq.kirmanak.mealient.datasource.models.VersionResponse
|
import gq.kirmanak.mealient.datasource.models.VersionResponse
|
||||||
|
import gq.kirmanak.mealient.datasource.v1.models.GetRecipeSummaryResponseV1
|
||||||
|
|
||||||
interface MealieDataSourceV1 {
|
interface MealieDataSourceV1 {
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ interface MealieDataSourceV1 {
|
|||||||
token: String?,
|
token: String?,
|
||||||
start: Int,
|
start: Int,
|
||||||
limit: Int,
|
limit: Int,
|
||||||
): List<GetRecipeSummaryResponse>
|
): List<GetRecipeSummaryResponseV1>
|
||||||
|
|
||||||
suspend fun requestRecipeInfo(
|
suspend fun requestRecipeInfo(
|
||||||
baseUrl: String,
|
baseUrl: String,
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
package gq.kirmanak.mealient.datasource.v1
|
||||||
|
|
||||||
|
import gq.kirmanak.mealient.datasource.models.AddRecipeRequest
|
||||||
|
import gq.kirmanak.mealient.datasource.models.GetRecipeResponse
|
||||||
|
import gq.kirmanak.mealient.datasource.models.NetworkError
|
||||||
|
import gq.kirmanak.mealient.datasource.models.VersionResponse
|
||||||
|
import gq.kirmanak.mealient.datasource.v1.models.GetRecipeSummaryResponseV1
|
||||||
|
import gq.kirmanak.mealient.logging.Logger
|
||||||
|
import kotlinx.serialization.SerializationException
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
import retrofit2.HttpException
|
||||||
|
import java.net.ConnectException
|
||||||
|
import java.net.SocketTimeoutException
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
class MealieDataSourceV1Impl @Inject constructor(
|
||||||
|
private val logger: Logger,
|
||||||
|
private val mealieService: MealieServiceV1,
|
||||||
|
private val json: Json,
|
||||||
|
) : MealieDataSourceV1 {
|
||||||
|
|
||||||
|
override suspend fun addRecipe(
|
||||||
|
baseUrl: String,
|
||||||
|
token: String?,
|
||||||
|
recipe: AddRecipeRequest
|
||||||
|
): String {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun authenticate(baseUrl: String, username: String, password: String): String {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getVersionInfo(baseUrl: String): VersionResponse = makeCall(
|
||||||
|
block = { getVersion("$baseUrl/api/app/about") },
|
||||||
|
logMethod = { "getVersionInfo" },
|
||||||
|
logParameters = { "baseUrl = $baseUrl" },
|
||||||
|
).getOrElse {
|
||||||
|
throw when (it) {
|
||||||
|
is HttpException, is SerializationException -> NetworkError.NotMealie(it)
|
||||||
|
is SocketTimeoutException, is ConnectException -> NetworkError.NoServerConnection(it)
|
||||||
|
else -> NetworkError.MalformedUrl(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun requestRecipes(
|
||||||
|
baseUrl: String,
|
||||||
|
token: String?,
|
||||||
|
start: Int,
|
||||||
|
limit: Int
|
||||||
|
): List<GetRecipeSummaryResponseV1> {
|
||||||
|
// Imagine start is 30 and limit is 15. It means that we already have page 1 and 2, now we need page 3
|
||||||
|
val perPage = limit
|
||||||
|
val page = start / perPage + 1
|
||||||
|
return makeCall(
|
||||||
|
block = { getRecipeSummary("$baseUrl/api/recipes", token, page, perPage) },
|
||||||
|
logMethod = { "requestRecipesV1" },
|
||||||
|
logParameters = { "baseUrl = $baseUrl, token = $token, start = $start, limit = $limit" }
|
||||||
|
).map { it.items }.getOrThrowUnauthorized()
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun requestRecipeInfo(
|
||||||
|
baseUrl: String,
|
||||||
|
token: String?,
|
||||||
|
slug: String
|
||||||
|
): GetRecipeResponse {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend inline fun <T> makeCall(
|
||||||
|
crossinline block: suspend MealieServiceV1.() -> T,
|
||||||
|
crossinline logMethod: () -> String,
|
||||||
|
crossinline logParameters: () -> String,
|
||||||
|
): Result<T> {
|
||||||
|
logger.v { "${logMethod()} called with: ${logParameters()}" }
|
||||||
|
return mealieService.runCatching { block() }
|
||||||
|
.onFailure { logger.e(it) { "${logMethod()} request failed with: ${logParameters()}" } }
|
||||||
|
.onSuccess { logger.d { "${logMethod()} request succeeded with ${logParameters()}" } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun <T> Result<T>.getOrThrowUnauthorized(): T = getOrElse {
|
||||||
|
throw if (it is HttpException && it.code() in listOf(401, 403)) {
|
||||||
|
NetworkError.Unauthorized(it)
|
||||||
|
} else {
|
||||||
|
it
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
package gq.kirmanak.mealient.datasource
|
package gq.kirmanak.mealient.datasource.v1
|
||||||
|
|
||||||
import gq.kirmanak.mealient.datasource.DataSourceModule.Companion.AUTHORIZATION_HEADER_NAME
|
import gq.kirmanak.mealient.datasource.DataSourceModule.Companion.AUTHORIZATION_HEADER_NAME
|
||||||
import gq.kirmanak.mealient.datasource.models.*
|
import gq.kirmanak.mealient.datasource.models.*
|
||||||
|
import gq.kirmanak.mealient.datasource.v1.models.GetRecipesResponseV1
|
||||||
import retrofit2.http.*
|
import retrofit2.http.*
|
||||||
|
|
||||||
interface MealieServiceV1 {
|
interface MealieServiceV1 {
|
||||||
@@ -28,14 +29,6 @@ interface MealieServiceV1 {
|
|||||||
|
|
||||||
@GET
|
@GET
|
||||||
suspend fun getRecipeSummary(
|
suspend fun getRecipeSummary(
|
||||||
@Url url: String,
|
|
||||||
@Header(AUTHORIZATION_HEADER_NAME) token: String?,
|
|
||||||
@Query("start") start: Int,
|
|
||||||
@Query("limit") limit: Int,
|
|
||||||
): List<GetRecipeSummaryResponse>
|
|
||||||
|
|
||||||
@GET
|
|
||||||
suspend fun getRecipeSummaryV1(
|
|
||||||
@Url url: String,
|
@Url url: String,
|
||||||
@Header(AUTHORIZATION_HEADER_NAME) token: String?,
|
@Header(AUTHORIZATION_HEADER_NAME) token: String?,
|
||||||
@Query("page") page: Int,
|
@Query("page") page: Int,
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package gq.kirmanak.mealient.datasource.v1.models
|
||||||
|
|
||||||
|
import kotlinx.datetime.LocalDate
|
||||||
|
import kotlinx.datetime.LocalDateTime
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class GetRecipeSummaryResponseV1(
|
||||||
|
@SerialName("id") val remoteId: String,
|
||||||
|
@SerialName("name") val name: String,
|
||||||
|
@SerialName("slug") val slug: String,
|
||||||
|
@SerialName("image") val image: String?,
|
||||||
|
@SerialName("description") val description: String = "",
|
||||||
|
@SerialName("recipeCategory") val recipeCategories: List<String>,
|
||||||
|
@SerialName("tags") val tags: List<String>,
|
||||||
|
@SerialName("rating") val rating: Int?,
|
||||||
|
@SerialName("dateAdded") val dateAdded: LocalDate,
|
||||||
|
@SerialName("dateUpdated") val dateUpdated: LocalDateTime
|
||||||
|
) {
|
||||||
|
override fun toString(): String {
|
||||||
|
return "GetRecipeSummaryResponseV1(remoteId=$remoteId, name='$name')"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
package gq.kirmanak.mealient.datasource.models
|
package gq.kirmanak.mealient.datasource.v1.models
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class GetRecipesResponseV1(
|
data class GetRecipesResponseV1(
|
||||||
@SerialName("items") val items: List<GetRecipeSummaryResponse>,
|
@SerialName("items") val items: List<GetRecipeSummaryResponseV1>,
|
||||||
)
|
)
|
||||||
Reference in New Issue
Block a user