Fix series index and add it to the sort system.

This commit is contained in:
Thomas Andres Gomez 2022-10-16 18:44:52 +02:00
parent e69af172af
commit 46a1f568f1
16 changed files with 74 additions and 56 deletions

View file

@ -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')"
]
}
}

View file

@ -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"
}
}

View file

@ -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"
}
}

View file

@ -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,

View file

@ -4,5 +4,4 @@ data class Series(
val id: Int,
val name: String,
val sort: String,
val index: Int?,
)

View file

@ -7,8 +7,5 @@ import androidx.compose.runtime.Stable
@Immutable
enum class SortType {
Book,
Author,
Series,
Genre,
Language;
}

View file

@ -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

View file

@ -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 }
}
}

View file

@ -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,
)
}

View file

@ -11,6 +11,7 @@ interface ISearchRepository {
seriesId: Int?,
genreId: Int?,
languageId: Int?,
sortBy : SortType,
limit: Int,
offset: Int,
): List<Book>

View file

@ -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,
)

View file

@ -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 = "",
)
)
}

View file

@ -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
)

View file

@ -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 {

View file

@ -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

View file

@ -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
}
}