API completeness

This commit is contained in:
Syer10
2022-11-07 21:46:36 -05:00
parent a3fdf4286a
commit e9ed487cc9
14 changed files with 330 additions and 3 deletions

View File

@@ -0,0 +1,47 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package ca.gosyer.jui.domain.category.interactor
import ca.gosyer.jui.domain.category.model.Category
import ca.gosyer.jui.domain.category.service.CategoryRepository
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.flow
import me.tatarka.inject.annotations.Inject
import org.lighthousegames.logging.logging
class UpdateCategoryMeta @Inject constructor(private val categoryRepository: CategoryRepository) {
suspend fun await(
category: Category,
example: Int = category.meta.example,
onError: suspend (Throwable) -> Unit = {}
) = asFlow(category, example)
.catch {
onError(it)
log.warn(it) { "Failed to update ${category.name}(${category.id}) meta" }
}
.collect()
fun asFlow(
category: Category,
example: Int = category.meta.example,
) = flow {
if (example != category.meta.example) {
categoryRepository.updateCategoryMeta(
category.id,
"example",
example.toString()
).collect()
}
emit(Unit)
}
companion object {
private val log = logging()
}
}

View File

@@ -15,5 +15,12 @@ data class Category(
val id: Long,
val order: Int,
val name: String,
val default: Boolean
val default: Boolean,
val meta: CategoryMeta
)
@Serializable
@Immutable
data class CategoryMeta(
val example: Int = 0
)

View File

@@ -68,4 +68,12 @@ interface CategoryRepository {
fun getMangaFromCategory(
@Path("categoryId") categoryId: Long
): Flow<List<Manga>>
@FormUrlEncoded
@PATCH("api/v1/category/{categoryId}/meta")
fun updateCategoryMeta(
@Path("categoryId") categoryId: Long,
@Field("key") key: String,
@Field("value") value: String
): Flow<HttpResponse>
}

View File

@@ -0,0 +1,49 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package ca.gosyer.jui.domain.download.interactor
import ca.gosyer.jui.domain.chapter.model.Chapter
import ca.gosyer.jui.domain.download.service.DownloadRepository
import ca.gosyer.jui.domain.manga.model.Manga
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.collect
import me.tatarka.inject.annotations.Inject
import org.lighthousegames.logging.logging
class ReorderChapterDownload @Inject constructor(private val downloadRepository: DownloadRepository) {
suspend fun await(mangaId: Long, index: Int, to: Int, onError: suspend (Throwable) -> Unit = {}) = asFlow(mangaId, index, to)
.catch {
onError(it)
log.warn(it) { "Failed to reorder chapter download for $index of $mangaId to $to" }
}
.collect()
suspend fun await(manga: Manga, index: Int, to: Int, onError: suspend (Throwable) -> Unit = {}) = asFlow(manga, index, to)
.catch {
onError(it)
log.warn(it) { "Failed to reorder chapter download for $index of ${manga.title}(${manga.id}) to $to" }
}
.collect()
suspend fun await(chapter: Chapter, to: Int, onError: suspend (Throwable) -> Unit = {}) = asFlow(chapter, to)
.catch {
onError(it)
log.warn(it) { "Failed to reorder chapter download for ${chapter.index} of ${chapter.mangaId} to $to" }
}
.collect()
fun asFlow(mangaId: Long, index: Int, to: Int) = downloadRepository.reorderChapterDownload(mangaId, index, to)
fun asFlow(manga: Manga, index: Int, to: Int) = downloadRepository.reorderChapterDownload(manga.id, index, to)
fun asFlow(chapter: Chapter, to: Int) = downloadRepository.reorderChapterDownload(chapter.mangaId, chapter.index, to)
companion object {
private val log = logging()
}
}

View File

@@ -11,6 +11,7 @@ import de.jensklingenberg.ktorfit.http.Body
import de.jensklingenberg.ktorfit.http.DELETE
import de.jensklingenberg.ktorfit.http.GET
import de.jensklingenberg.ktorfit.http.Headers
import de.jensklingenberg.ktorfit.http.PATCH
import de.jensklingenberg.ktorfit.http.POST
import de.jensklingenberg.ktorfit.http.Path
import io.ktor.client.statement.HttpResponse
@@ -38,6 +39,13 @@ interface DownloadRepository {
@Path("chapterIndex") chapterIndex: Int
): Flow<HttpResponse>
@PATCH("api/v1/download/{mangaId}/chapter/{chapterIndex}/reorder/{to}")
fun reorderChapterDownload(
@Path("mangaId") mangaId: Long,
@Path("chapterIndex") chapterIndex: Int,
@Path("to") to: Int
): Flow<HttpResponse>
@POST("api/v1/download/batch")
@Headers("Content-Type: application/json")
fun batchDownload(

View File

@@ -0,0 +1,29 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package ca.gosyer.jui.domain.global.interactor
import ca.gosyer.jui.domain.global.service.GlobalRepository
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.singleOrNull
import me.tatarka.inject.annotations.Inject
import org.lighthousegames.logging.logging
class GetGlobalMeta @Inject constructor(private val globalRepository: GlobalRepository) {
suspend fun await(onError: suspend (Throwable) -> Unit = {}) = asFlow()
.catch {
onError(it)
log.warn(it) { "Failed to get global meta" }
}
.singleOrNull()
fun asFlow() = globalRepository.getGlobalMeta()
companion object {
private val log = logging()
}
}

View File

@@ -0,0 +1,46 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package ca.gosyer.jui.domain.global.interactor
import ca.gosyer.jui.domain.global.model.GlobalMeta
import ca.gosyer.jui.domain.global.service.GlobalRepository
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.flow
import me.tatarka.inject.annotations.Inject
import org.lighthousegames.logging.logging
class UpdateGlobalMeta @Inject constructor(private val globalRepository: GlobalRepository) {
suspend fun await(
globalMeta: GlobalMeta,
example: Int = globalMeta.example,
onError: suspend (Throwable) -> Unit = {}
) = asFlow(globalMeta, example)
.catch {
onError(it)
log.warn(it) { "Failed to update global meta" }
}
.collect()
fun asFlow(
globalMeta: GlobalMeta,
example: Int = globalMeta.example,
) = flow {
if (example != globalMeta.example) {
globalRepository.updateGlobalMeta(
"example",
example.toString()
).collect()
}
emit(Unit)
}
companion object {
private val log = logging()
}
}

View File

@@ -0,0 +1,16 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package ca.gosyer.jui.domain.global.model
import androidx.compose.runtime.Immutable
import kotlinx.serialization.Serializable
@Serializable
@Immutable
data class GlobalMeta(
val example: Int = 0
)

View File

@@ -0,0 +1,27 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package ca.gosyer.jui.domain.global.service
import ca.gosyer.jui.domain.global.model.GlobalMeta
import de.jensklingenberg.ktorfit.http.Field
import de.jensklingenberg.ktorfit.http.FormUrlEncoded
import de.jensklingenberg.ktorfit.http.GET
import de.jensklingenberg.ktorfit.http.PATCH
import io.ktor.client.statement.HttpResponse
import kotlinx.coroutines.flow.Flow
interface GlobalRepository {
@GET("api/v1/meta")
fun getGlobalMeta(): Flow<GlobalMeta>
@FormUrlEncoded
@PATCH("api/v1/meta")
fun updateGlobalMeta(
@Field("key") key: String,
@Field("value") value: String
): Flow<HttpResponse>
}

View File

@@ -0,0 +1,55 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package ca.gosyer.jui.domain.source.interactor
import ca.gosyer.jui.domain.source.model.Source
import ca.gosyer.jui.domain.source.model.sourcefilters.SourceFilterChange
import ca.gosyer.jui.domain.source.model.sourcefilters.SourceFilterData
import ca.gosyer.jui.domain.source.service.SourceRepository
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.singleOrNull
import me.tatarka.inject.annotations.Inject
import org.lighthousegames.logging.logging
class GetQuickSearchManga @Inject constructor(private val sourceRepository: SourceRepository) {
suspend fun await(source: Source, searchTerm: String?, page: Int, filters: List<SourceFilterChange>?, onError: suspend (Throwable) -> Unit = {}) = asFlow(source.id, searchTerm, page, filters)
.catch {
onError(it)
log.warn(it) { "Failed to get quick search results from ${source.displayName} on page $page with query '$searchTerm'" }
}
.singleOrNull()
suspend fun await(sourceId: Long, searchTerm: String?, page: Int, filters: List<SourceFilterChange>?, onError: suspend (Throwable) -> Unit = {}) = asFlow(sourceId, searchTerm, page, filters)
.catch {
onError(it)
log.warn(it) { "Failed to get quick search results from $sourceId on page $page with query '$searchTerm'" }
}
.singleOrNull()
fun asFlow(source: Source, searchTerm: String?, page: Int, filters: List<SourceFilterChange>?) = sourceRepository.getQuickSearchResults(
source.id,
page,
SourceFilterData(
searchTerm?.ifBlank { null },
filters?.ifEmpty { null }
)
)
fun asFlow(sourceId: Long, searchTerm: String?, page: Int, filters: List<SourceFilterChange>?) = sourceRepository.getQuickSearchResults(
sourceId,
page,
SourceFilterData(
searchTerm?.ifBlank { null },
filters?.ifEmpty { null }
)
)
companion object {
private val log = logging()
}
}

View File

@@ -0,0 +1,15 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package ca.gosyer.jui.domain.source.model.sourcefilters
import kotlinx.serialization.Serializable
@Serializable
data class SourceFilterData(
val searchTerm: String?,
val filter: List<SourceFilterChange>?
)

View File

@@ -10,6 +10,7 @@ import ca.gosyer.jui.domain.source.model.MangaPage
import ca.gosyer.jui.domain.source.model.Source
import ca.gosyer.jui.domain.source.model.sourcefilters.SourceFilter
import ca.gosyer.jui.domain.source.model.sourcefilters.SourceFilterChange
import ca.gosyer.jui.domain.source.model.sourcefilters.SourceFilterData
import ca.gosyer.jui.domain.source.model.sourcepreference.SourcePreference
import ca.gosyer.jui.domain.source.model.sourcepreference.SourcePreferenceChange
import de.jensklingenberg.ktorfit.http.Body
@@ -62,6 +63,21 @@ interface SourceRepository {
@Body sourceFilter: SourceFilterChange
): Flow<HttpResponse>
@POST("api/v1/source/{sourceId}/filters")
@Headers("Content-Type: application/json")
fun setFilters(
@Path("sourceId") sourceId: Long,
@Body sourceFilters: List<SourceFilterChange>
): Flow<HttpResponse>
@POST("api/v1/source/{sourceId}/quick-search")
@Headers("Content-Type: application/json")
fun getQuickSearchResults(
@Path("sourceId") sourceId: Long,
@Query("pageNum") pageNum: Int,
@Body filterData: SourceFilterData
): Flow<MangaPage>
@GET("api/v1/source/{sourceId}/preferences")
fun getSourceSettings(
@Path("sourceId") sourceId: Long