Fix series index and add it to the sort system.
This commit is contained in:
parent
e69af172af
commit
46a1f568f1
16 changed files with 74 additions and 56 deletions
|
|
@ -2,7 +2,7 @@
|
|||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 1,
|
||||
"identityHash": "3f612998c4903a247d1c955da20b272d",
|
||||
"identityHash": "96272f43076988345569b6ad637a4e01",
|
||||
"entities": [
|
||||
{
|
||||
"tableName": "AUTHOR",
|
||||
|
|
@ -38,7 +38,7 @@
|
|||
},
|
||||
{
|
||||
"tableName": "BOOK",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`BOOK_ID` INTEGER NOT NULL, `BOOK_TITLE` TEXT NOT NULL, `BOOK_SORT` TEXT NOT NULL, `BOOK_HAVE_COVER` INTEGER NOT NULL, `BOOK_RELEASE_DATE` INTEGER NOT NULL, `BOOK_LANGUAGE_ID` INTEGER, `BOOK_RATING` INTEGER, `BOOK_SERIES_ID` INTEGER, `BOOK_SYNOPSIS` TEXT, `BOOK_ISNEW` INTEGER NOT NULL, `BOOK_NEW_ORDER` INTEGER, PRIMARY KEY(`BOOK_ID`))",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`BOOK_ID` INTEGER NOT NULL, `BOOK_TITLE` TEXT NOT NULL, `BOOK_SORT` TEXT NOT NULL, `BOOK_HAVE_COVER` INTEGER NOT NULL, `BOOK_RELEASE_DATE` INTEGER NOT NULL, `BOOK_LANGUAGE_ID` INTEGER, `BOOK_RATING` INTEGER, `BOOK_SERIES_ID` INTEGER, `BOOK_SERIES_INDEX` INTEGER, `BOOK_SYNOPSIS` TEXT, `BOOK_IS_NEW` INTEGER NOT NULL, `BOOK_NEW_ORDER` INTEGER, PRIMARY KEY(`BOOK_ID`))",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
|
|
@ -88,6 +88,12 @@
|
|||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "seriesIndex",
|
||||
"columnName": "BOOK_SERIES_INDEX",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "synopsis",
|
||||
"columnName": "BOOK_SYNOPSIS",
|
||||
|
|
@ -96,7 +102,7 @@
|
|||
},
|
||||
{
|
||||
"fieldPath": "isNew",
|
||||
"columnName": "BOOK_ISNEW",
|
||||
"columnName": "BOOK_IS_NEW",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
|
|
@ -170,7 +176,7 @@
|
|||
},
|
||||
{
|
||||
"tableName": "SERIES",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`SERIES_ID` INTEGER NOT NULL, `SERIES_NAME` TEXT NOT NULL, `SERIES_SORT` TEXT NOT NULL, `SERIES_INDEX` INTEGER, PRIMARY KEY(`SERIES_ID`))",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`SERIES_ID` INTEGER NOT NULL, `SERIES_NAME` TEXT NOT NULL, `SERIES_SORT` TEXT NOT NULL, PRIMARY KEY(`SERIES_ID`))",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
|
|
@ -189,12 +195,6 @@
|
|||
"columnName": "SERIES_SORT",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "index",
|
||||
"columnName": "SERIES_INDEX",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
|
|
@ -284,7 +284,7 @@
|
|||
"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, '3f612998c4903a247d1c955da20b272d')"
|
||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '96272f43076988345569b6ad637a4e01')"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -25,6 +25,8 @@ data class BookDbo(
|
|||
// details
|
||||
@ColumnInfo(name = SERIES_ID)
|
||||
val series: Int? = null, // one-to-many
|
||||
@ColumnInfo(name = SERIES_INDEX)
|
||||
val seriesIndex: Int? = null,
|
||||
@ColumnInfo(name = SYNOPSIS)
|
||||
val synopsis: String? = null,
|
||||
// source
|
||||
|
|
@ -54,8 +56,9 @@ data class BookDbo(
|
|||
const val LANGUAGE_ID = "${TABLE}_LANGUAGE_ID"
|
||||
const val RATING = "${TABLE}_RATING"
|
||||
const val SERIES_ID = "${TABLE}_SERIES_ID"
|
||||
const val SERIES_INDEX = "${TABLE}_SERIES_INDEX"
|
||||
const val SYNOPSIS = "${TABLE}_SYNOPSIS"
|
||||
const val IS_NEW = "${TABLE}_ISNEW"
|
||||
const val IS_NEW = "${TABLE}_IS_NEW"
|
||||
const val NEW_ORDER = "${TABLE}_NEW_ORDER"
|
||||
}
|
||||
}
|
||||
|
|
@ -13,14 +13,11 @@ data class SeriesDbo(
|
|||
val name: String,
|
||||
@ColumnInfo(name = SORT)
|
||||
val sort: String,
|
||||
@ColumnInfo(name = INDEX)
|
||||
val index: Int?,
|
||||
) {
|
||||
companion object {
|
||||
const val TABLE = "SERIES"
|
||||
const val ID = "${TABLE}_ID"
|
||||
const val NAME = "${TABLE}_NAME"
|
||||
const val SORT = "${TABLE}_SORT"
|
||||
const val INDEX = "${TABLE}_INDEX"
|
||||
}
|
||||
}
|
||||
|
|
@ -14,6 +14,7 @@ data class Book(
|
|||
val genre: List<Genre>? = null,
|
||||
// details
|
||||
val series: Series? = null,
|
||||
val seriesIndex: Int? = null,
|
||||
val synopsis: String? = null,
|
||||
// source
|
||||
val isNew: Boolean = false,
|
||||
|
|
|
|||
|
|
@ -4,5 +4,4 @@ data class Series(
|
|||
val id: Int,
|
||||
val name: String,
|
||||
val sort: String,
|
||||
val index: Int?,
|
||||
)
|
||||
|
|
@ -7,8 +7,5 @@ import androidx.compose.runtime.Stable
|
|||
@Immutable
|
||||
enum class SortType {
|
||||
Book,
|
||||
Author,
|
||||
Series,
|
||||
Genre,
|
||||
Language;
|
||||
}
|
||||
|
|
@ -13,7 +13,7 @@ class BookFactory {
|
|||
|
||||
fun fromListResponseToBook(
|
||||
response: BookListResponse.Book,
|
||||
seriesHash: Map<Int, Series>,
|
||||
seriesHash: SeriesHash,
|
||||
genreHash: Map<Int, List<Genre>>,
|
||||
isNew: Boolean = false,
|
||||
newOrder: Int? = null
|
||||
|
|
@ -63,12 +63,6 @@ class BookFactory {
|
|||
}
|
||||
val rating = response.rating?.toIntOrNull()
|
||||
|
||||
val newOrder = if (isNew) {
|
||||
newOrder
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
return Book(
|
||||
id = id ?: throw error("id"),
|
||||
title = title ?: throw error("title"),
|
||||
|
|
@ -76,12 +70,13 @@ class BookFactory {
|
|||
author = author ?: throw error("author"),
|
||||
haveCover = cover ?: throw error("haveCover"),
|
||||
releaseDate = releaseDate ?: throw error("releaseDate"),
|
||||
series = seriesHash[id],
|
||||
series = seriesHash[id]?.second,
|
||||
seriesIndex = seriesHash[id]?.first,
|
||||
language = language,
|
||||
rating = rating,
|
||||
genre = genreHash[id],
|
||||
isNew = isNew,
|
||||
newOrder = newOrder,
|
||||
newOrder = if (isNew) newOrder else null,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -126,7 +121,7 @@ class BookFactory {
|
|||
val seriesSort = book.series_sort
|
||||
val seriesIndex: Int? = book.book_series_index?.toInt()
|
||||
val series: Series? = if (seriesId != null && seriesName != null && seriesSort != null) {
|
||||
Series(id = seriesId, name = seriesName, sort = seriesSort, seriesIndex)
|
||||
Series(id = seriesId, name = seriesName, sort = seriesSort)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
|
@ -151,6 +146,7 @@ class BookFactory {
|
|||
language = language ?: throw error("language"),
|
||||
rating = rating,
|
||||
series = series,
|
||||
seriesIndex = seriesIndex,
|
||||
genre = tag,
|
||||
synopsis = synopsis,
|
||||
isNew = isNew
|
||||
|
|
|
|||
|
|
@ -4,26 +4,28 @@ import com.pixelized.biblib.model.book.Series
|
|||
import com.pixelized.biblib.network.data.response.SeriesListResponse
|
||||
import com.pixelized.biblib.utils.exception.missingField
|
||||
|
||||
typealias SeriesHash = Map<Int, Pair<Int, Series>>
|
||||
|
||||
class SeriesFactory {
|
||||
|
||||
fun fromListResponseToSeriesHash(
|
||||
response: SeriesListResponse,
|
||||
): Map<Int, Series> {
|
||||
): SeriesHash {
|
||||
fun error(name: String) = missingField("#fromListResponseToSeriesHash()", name, response)
|
||||
|
||||
val hash = mutableMapOf<Int, Series>()
|
||||
// BOOK_ID, BOOK_SERIES_INDEX, SERIES
|
||||
val hash = mutableMapOf<Int, Pair<Int, Series>>()
|
||||
|
||||
response.series?.forEachIndexed { index, data ->
|
||||
response.series?.forEach { data ->
|
||||
// build the Series items
|
||||
val series = Series(
|
||||
id = data.series_id ?: throw error("id"),
|
||||
name = data.series_name ?: throw error("name"),
|
||||
sort = data.series_sort ?: throw error("sort"),
|
||||
index = index,
|
||||
)
|
||||
// link that item to the book id.
|
||||
data.books?.forEach { book ->
|
||||
book.book_id?.let { id -> hash[id] = series }
|
||||
data.books?.forEachIndexed { index, book ->
|
||||
book.book_id?.let { id -> hash[id] = (index + 1) to series }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -61,9 +61,7 @@ class BookRepository @Inject constructor(
|
|||
languages.add(it.toDbo())
|
||||
}
|
||||
book.series?.let {
|
||||
if (it.id != null) {
|
||||
series.add(it.toDbo(it.id))
|
||||
}
|
||||
series.add(it.toDbo(it.id))
|
||||
}
|
||||
books.add(book.toDbo())
|
||||
}
|
||||
|
|
@ -93,7 +91,6 @@ class BookRepository @Inject constructor(
|
|||
id = id,
|
||||
name = name,
|
||||
sort = sort,
|
||||
index = index,
|
||||
)
|
||||
|
||||
private fun Language.toDbo() = LanguageDbo(
|
||||
|
|
@ -110,6 +107,7 @@ class BookRepository @Inject constructor(
|
|||
language = language?.id,
|
||||
rating = rating,
|
||||
series = series?.id,
|
||||
seriesIndex = seriesIndex,
|
||||
synopsis = synopsis,
|
||||
isNew = isNew,
|
||||
newOrder = newOrder,
|
||||
|
|
@ -126,6 +124,7 @@ class BookRepository @Inject constructor(
|
|||
rating = book.rating,
|
||||
genre = genres?.map { it.toGenre() },
|
||||
series = series?.toSeries(),
|
||||
seriesIndex = book.seriesIndex,
|
||||
synopsis = book.synopsis,
|
||||
isNew = book.isNew,
|
||||
)
|
||||
|
|
@ -150,6 +149,5 @@ class BookRepository @Inject constructor(
|
|||
id = id,
|
||||
name = name,
|
||||
sort = sort,
|
||||
index = index,
|
||||
)
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@ interface ISearchRepository {
|
|||
seriesId: Int?,
|
||||
genreId: Int?,
|
||||
languageId: Int?,
|
||||
sortBy : SortType,
|
||||
limit: Int,
|
||||
offset: Int,
|
||||
): List<Book>
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ class SearchRepository @Inject constructor(
|
|||
seriesId: Int?,
|
||||
genreId: Int?,
|
||||
languageId: Int?,
|
||||
sortBy : SortType,
|
||||
limit: Int,
|
||||
offset: Int
|
||||
): List<Book> {
|
||||
|
|
@ -43,7 +44,10 @@ class SearchRepository @Inject constructor(
|
|||
query += args.where(argument = languageId) {
|
||||
BookDbo.run { "$TABLE.$LANGUAGE_ID LIKE ?" }
|
||||
}
|
||||
query += BookDbo.run { " ORDER BY $TABLE.$SORT" }
|
||||
query += when (sortBy) {
|
||||
SortType.Book -> BookDbo.run { " ORDER BY $TABLE.$SORT" }
|
||||
SortType.Series -> BookDbo.run { " ORDER BY $TABLE.$SERIES_INDEX" }
|
||||
}
|
||||
// Limit and Offset the query.
|
||||
query += " LIMIT $limit OFFSET $offset;"
|
||||
// compute the query
|
||||
|
|
@ -143,6 +147,7 @@ private fun BookRelation.toBook(): Book = Book(
|
|||
rating = book.rating,
|
||||
genre = genres?.map { it.toGenre() },
|
||||
series = series?.toSeries(),
|
||||
seriesIndex = book.seriesIndex,
|
||||
synopsis = book.synopsis,
|
||||
isNew = book.isNew,
|
||||
)
|
||||
|
|
@ -167,5 +172,4 @@ private fun SeriesDbo.toSeries() = Series(
|
|||
id = id,
|
||||
name = name,
|
||||
sort = sort,
|
||||
index = index,
|
||||
)
|
||||
|
|
@ -29,10 +29,11 @@ import com.skydoves.landscapist.glide.GlideImage
|
|||
@Stable
|
||||
data class MicroBookThumbnailUio(
|
||||
val id: Int,
|
||||
val cover: String,
|
||||
val title: String,
|
||||
val author: String,
|
||||
val series: String,
|
||||
val isNew: Boolean,
|
||||
val cover: String,
|
||||
)
|
||||
|
||||
@Composable
|
||||
|
|
@ -71,7 +72,7 @@ private fun MicroBookThumbnailContent(
|
|||
ConstraintLayout(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
) {
|
||||
val (cover, title, author) = createRefs()
|
||||
val (cover, title, author, series) = createRefs()
|
||||
|
||||
GlideImage(
|
||||
modifier = Modifier
|
||||
|
|
@ -95,25 +96,37 @@ private fun MicroBookThumbnailContent(
|
|||
},
|
||||
style = MaterialTheme.typography.body1,
|
||||
color = MaterialTheme.bibLib.colors.typography.medium,
|
||||
text = thumbnail.title,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
text = thumbnail.title,
|
||||
)
|
||||
|
||||
Text(
|
||||
modifier = Modifier.constrainAs(author) {
|
||||
top.linkTo(title.bottom, margin = dimen.dp4)
|
||||
bottom.linkTo(parent.bottom, margin = dimen.dp4)
|
||||
start.linkTo(cover.end, margin = dimen.dp8)
|
||||
end.linkTo(parent.end, margin = dimen.dp8)
|
||||
width = Dimension.fillToConstraints
|
||||
height = Dimension.fillToConstraints
|
||||
},
|
||||
style = MaterialTheme.typography.caption,
|
||||
color = MaterialTheme.bibLib.colors.typography.easy,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
text = thumbnail.author
|
||||
maxLines = 1,
|
||||
text = thumbnail.author,
|
||||
)
|
||||
|
||||
Text(
|
||||
modifier = Modifier.constrainAs(series) {
|
||||
top.linkTo(author.bottom, margin = dimen.dp4)
|
||||
start.linkTo(cover.end, margin = dimen.dp8)
|
||||
end.linkTo(parent.end, margin = dimen.dp8)
|
||||
width = Dimension.fillToConstraints
|
||||
},
|
||||
style = MaterialTheme.typography.caption,
|
||||
color = MaterialTheme.bibLib.colors.typography.easy,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
text = thumbnail.series,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -186,10 +199,11 @@ private fun MicroBookThumbnailPreview() {
|
|||
MicroBookThumbnail(
|
||||
thumbnail = MicroBookThumbnailUio(
|
||||
id = 0,
|
||||
cover = "",
|
||||
title = "Foundation",
|
||||
author = "Asimov",
|
||||
series = "Foundation - 1",
|
||||
isNew = false,
|
||||
cover = "",
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import android.util.Log
|
|||
import androidx.paging.PagingSource
|
||||
import androidx.paging.PagingState
|
||||
import com.pixelized.biblib.model.book.Book
|
||||
import com.pixelized.biblib.model.search.SortType
|
||||
import com.pixelized.biblib.repository.search.ISearchRepository
|
||||
import com.pixelized.biblib.utils.extention.page
|
||||
|
||||
|
|
@ -13,6 +14,7 @@ class BookSearchSource(
|
|||
private val authorId: Int?,
|
||||
private val seriesId: Int?,
|
||||
private val genreId: Int?,
|
||||
private val sortBy: SortType,
|
||||
private val languageId: Int?,
|
||||
private val limit: Int,
|
||||
) : PagingSource<Int, Book>() {
|
||||
|
|
@ -30,6 +32,7 @@ class BookSearchSource(
|
|||
seriesId = seriesId,
|
||||
genreId = genreId,
|
||||
languageId = languageId,
|
||||
sortBy = sortBy,
|
||||
limit = limit,
|
||||
offset = index * limit
|
||||
)
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import androidx.lifecycle.ViewModel
|
|||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.paging.*
|
||||
import com.pixelized.biblib.model.book.Book
|
||||
import com.pixelized.biblib.model.search.SortType
|
||||
import com.pixelized.biblib.repository.search.ISearchRepository
|
||||
import com.pixelized.biblib.ui.screen.home.common.item.MicroBookThumbnailUio
|
||||
import com.pixelized.biblib.ui.screen.home.page.search.bottom.FilterUio
|
||||
|
|
@ -83,6 +84,7 @@ class BookSearchViewModel @Inject constructor(
|
|||
authorId = author?.id,
|
||||
seriesId = series?.id,
|
||||
genreId = genre?.id,
|
||||
sortBy = if (series != null) SortType.Series else SortType.Book,
|
||||
languageId = language?.id,
|
||||
limit = SEARCH_PAGE_SIZE,
|
||||
).also {
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ data class BibLibDimen(
|
|||
val padding: Dp = 16.dp,
|
||||
val arrangement: Dp = 16.dp,
|
||||
val cover: DpSize = 72.dp.let { DpSize(width = it, height = it * ratio) },
|
||||
val micro: DpSize = 48.dp.let { DpSize(width = it, height = it * ratio) },
|
||||
val micro: DpSize = 50.dp.let { DpSize(width = it, height = it * ratio) },
|
||||
)
|
||||
|
||||
@Stable
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ fun Book.toMicroThumbnailUio(
|
|||
cover = "${coverBaseUrl}/$id.jpg",
|
||||
title = title,
|
||||
author = author.joinToString { it.name },
|
||||
series = toLabel(series) ?: "",
|
||||
isNew = isNew,
|
||||
)
|
||||
|
||||
|
|
@ -59,15 +60,15 @@ fun Book.toDetailUio(
|
|||
rating = rating?.toFloat() ?: 0.0f,
|
||||
language = language?.displayLanguage?.capitalize() ?: "",
|
||||
date = releaseDate.shortDate(),
|
||||
series = series.toLabel(),
|
||||
series = toLabel(series),
|
||||
description = synopsis ?: "",
|
||||
cover = "${coverBaseUrl}/$id.jpg",
|
||||
)
|
||||
|
||||
fun Series?.toLabel(): String? {
|
||||
fun Book.toLabel(series: Series?): String? {
|
||||
return when {
|
||||
this != null && index != null -> "$name - $index"
|
||||
this != null -> name
|
||||
series?.name != null && seriesIndex != null -> "${series.name} - $seriesIndex"
|
||||
series?.name != null -> series.name
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue