Add new book management

This commit is contained in:
Thomas Andres Gomez 2021-05-18 14:00:30 +02:00
parent bb9e1b36f7
commit a822d7f008
12 changed files with 63 additions and 236 deletions

View file

@ -28,6 +28,7 @@ class BibLibApplication : Application() {
// Android. // Android.
Bob[BibLibDatabase::class] = Bob[BibLibDatabase::class] =
Room.databaseBuilder(this, BibLibDatabase::class.java, BibLibDatabase.DATABASE_NAME) Room.databaseBuilder(this, BibLibDatabase::class.java, BibLibDatabase.DATABASE_NAME)
.fallbackToDestructiveMigration()
.build() .build()
Bob[SharedPreferences::class] = getSharedPreferences(SHARED_PREF, Context.MODE_PRIVATE) Bob[SharedPreferences::class] = getSharedPreferences(SHARED_PREF, Context.MODE_PRIVATE)
// Web service. // Web service.

View file

@ -11,6 +11,10 @@ interface BookDao {
@Query("SELECT * FROM ${BookDbo.TABLE}") @Query("SELECT * FROM ${BookDbo.TABLE}")
fun getAll(): List<BookRelation> fun getAll(): List<BookRelation>
@Transaction
@Query("SELECT * FROM ${BookDbo.TABLE} WHERE ${BookDbo.IS_NEW} = 1 ORDER BY ${BookDbo.NEW_ORDER}")
fun getNews(): DataSource.Factory<Int, BookRelation>
@Transaction @Transaction
@Query("SELECT * FROM ${BookDbo.TABLE}") @Query("SELECT * FROM ${BookDbo.TABLE}")
fun getBook(): DataSource.Factory<Int, BookRelation> fun getBook(): DataSource.Factory<Int, BookRelation>

View file

@ -30,6 +30,8 @@ data class BookDbo(
// source // source
@ColumnInfo(name = IS_NEW) @ColumnInfo(name = IS_NEW)
val isNew: Boolean = false, val isNew: Boolean = false,
@ColumnInfo(name = NEW_ORDER)
val newOrder: Int? = null,
) { ) {
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
if (this === other) return true if (this === other) return true
@ -54,5 +56,6 @@ data class BookDbo(
const val SERIES_ID = "${TABLE}_SERIES_ID" const val SERIES_ID = "${TABLE}_SERIES_ID"
const val SYNOPSIS = "${TABLE}_SYNOPSIS" const val SYNOPSIS = "${TABLE}_SYNOPSIS"
const val IS_NEW = "${TABLE}_ISNEW" const val IS_NEW = "${TABLE}_ISNEW"
const val NEW_ORDER = "${TABLE}_NEW_ORDER"
} }
} }

View file

@ -17,6 +17,7 @@ data class Book(
val synopsis: String? = null, val synopsis: String? = null,
// source // source
val isNew: Boolean = false, val isNew: Boolean = false,
val newOrder: Int? = null,
) { ) {
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
if (this === other) return true if (this === other) return true

View file

@ -11,7 +11,11 @@ import java.util.*
class BookFactory { class BookFactory {
private val parser get() = SimpleDateFormat(FORMAT, Locale.getDefault()) private val parser get() = SimpleDateFormat(FORMAT, Locale.getDefault())
fun fromListResponseToBook(response: BookListResponse.Book, isNew: Boolean = false): Book { fun fromListResponseToBook(
response: BookListResponse.Book,
isNew: Boolean = false,
newOrder: Int? = null
): Book {
fun error(name: String) = fun error(name: String) =
MandatoryFieldMissingException("#fromListResponseToBook()", name, response) MandatoryFieldMissingException("#fromListResponseToBook()", name, response)
@ -65,6 +69,11 @@ class BookFactory {
} else { } else {
null null
} }
val newOrder = if (isNew) {
newOrder
} else {
null
}
return Book( return Book(
id = id ?: throw error("id"), id = id ?: throw error("id"),
@ -76,7 +85,8 @@ class BookFactory {
series = series, series = series,
language = language, language = language,
rating = rating, rating = rating,
isNew = isNew isNew = isNew,
newOrder = newOrder,
) )
} }

View file

@ -1,7 +1,6 @@
package com.pixelized.biblib.repository.book package com.pixelized.biblib.repository.book
import android.util.Log
import androidx.paging.DataSource import androidx.paging.DataSource
import com.pixelized.biblib.database.BibLibDatabase import com.pixelized.biblib.database.BibLibDatabase
import com.pixelized.biblib.database.crossref.BookAuthorCrossRef import com.pixelized.biblib.database.crossref.BookAuthorCrossRef
@ -17,6 +16,9 @@ class BookRepository : IBookRepository {
override fun getAll(): List<Book> = override fun getAll(): List<Book> =
database.bookDao().getAll().map { it.toBook() } database.bookDao().getAll().map { it.toBook() }
override fun getNews(): DataSource.Factory<Int, Book> =
database.bookDao().getNews().map { it.toBook() }
override fun getBook(): DataSource.Factory<Int, Book> = override fun getBook(): DataSource.Factory<Int, Book> =
database.bookDao().getBook().map { it.toBook() } database.bookDao().getBook().map { it.toBook() }
@ -92,6 +94,7 @@ class BookRepository : IBookRepository {
series = series?.id, series = series?.id,
synopsis = synopsis, synopsis = synopsis,
isNew = isNew, isNew = isNew,
newOrder = newOrder,
) )
private fun BookRelation.toBook(): Book = Book( private fun BookRelation.toBook(): Book = Book(

View file

@ -7,6 +7,8 @@ interface IBookRepository {
fun getAll(): List<Book> fun getAll(): List<Book>
fun getNews(): DataSource.Factory<Int, Book>
fun getBook(): DataSource.Factory<Int, Book> fun getBook(): DataSource.Factory<Int, Book>
suspend fun update(data: List<Book>) suspend fun update(data: List<Book>)

View file

@ -74,7 +74,7 @@ fun MainScreenComposable(
) { ) {
Box { Box {
val lazyBooks: LazyPagingItems<BookThumbnailUio> = val lazyBooks: LazyPagingItems<BookThumbnailUio> =
booksViewModel.books.collectAsLazyPagingItems() booksViewModel.news.collectAsLazyPagingItems()
val lazyListState = rememberLazyListState() val lazyListState = rememberLazyListState()
val scrollableState = rememberScrollState() val scrollableState = rememberScrollState()

View file

@ -9,7 +9,8 @@ data class BookThumbnailUio(
val title: String, val title: String,
val author: String, val author: String,
val date: String, val date: String,
val series: String? val series: String?,
val isNew: Boolean,
) { ) {
val cover: URL = URL("${THUMBNAIL_URL}/$id.jpg") val cover: URL = URL("${THUMBNAIL_URL}/$id.jpg")
} }

View file

@ -29,14 +29,24 @@ class BooksViewModel : ViewModel(), IBooksViewModel {
private val _state = MutableLiveData<IBooksViewModel.State>(IBooksViewModel.State.Initial) private val _state = MutableLiveData<IBooksViewModel.State>(IBooksViewModel.State.Initial)
override val state: LiveData<IBooksViewModel.State> get() = _state override val state: LiveData<IBooksViewModel.State> get() = _state
private val source private val bookSource
get() = bookRepository.getBook() get() = bookRepository.getBook()
.map { it.toThumbnail() } .map { it.toThumbnail() }
.asPagingSourceFactory(Dispatchers.Default) .asPagingSourceFactory(Dispatchers.Default)
override val books: Flow<PagingData<BookThumbnailUio>> = Pager( override val books: Flow<PagingData<BookThumbnailUio>> = Pager(
config = PagingConfig(pageSize = PAGING_SIZE), config = PagingConfig(pageSize = PAGING_SIZE),
pagingSourceFactory = source pagingSourceFactory = bookSource
).flow
private val newsSource
get() = bookRepository.getNews()
.map { it.toThumbnail() }
.asPagingSourceFactory(Dispatchers.Default)
override val news: Flow<PagingData<BookThumbnailUio>> = Pager(
config = PagingConfig(pageSize = PAGING_SIZE),
pagingSourceFactory = newsSource
).flow ).flow
override fun updateBooks() { override fun updateBooks() {
@ -77,8 +87,13 @@ class BooksViewModel : ViewModel(), IBooksViewModel {
private suspend fun loadAllBooks(): Boolean { private suspend fun loadAllBooks(): Boolean {
client.service.list().let { response -> client.service.list().let { response ->
val newIds = apiCache.new?.data?.map { it.book_id } ?: listOf()
val factory = BookFactory() val factory = BookFactory()
val books = response.data?.map { dto -> factory.fromListResponseToBook(dto, false) } val books = response.data?.map { dto ->
val isNew = newIds.contains(dto.book_id)
val index = newIds.indexOf(dto.book_id)
factory.fromListResponseToBook(dto, isNew, index)
}
books?.let { data -> bookRepository.update(data) } books?.let { data -> bookRepository.update(data) }
} }
return true return true
@ -91,6 +106,7 @@ class BooksViewModel : ViewModel(), IBooksViewModel {
author = author.joinToString { it.name }, author = author.joinToString { it.name },
date = releaseDate.toString(), date = releaseDate.toString(),
series = series?.name, series = series?.name,
isNew = isNew,
) )
private fun Book.toUio() = BookUio( private fun Book.toUio() = BookUio(

View file

@ -11,6 +11,8 @@ import kotlinx.coroutines.flow.flowOf
interface IBooksViewModel { interface IBooksViewModel {
val state: LiveData<State> val state: LiveData<State>
val news: Flow<PagingData<BookThumbnailUio>>
val books: Flow<PagingData<BookThumbnailUio>> val books: Flow<PagingData<BookThumbnailUio>>
fun updateBooks() fun updateBooks()
@ -27,6 +29,9 @@ interface IBooksViewModel {
class Mock(initial: State = State.Initial) : IBooksViewModel { class Mock(initial: State = State.Initial) : IBooksViewModel {
override val state: LiveData<State> = MutableLiveData(initial) override val state: LiveData<State> = MutableLiveData(initial)
override val news: Flow<PagingData<BookThumbnailUio>>
get() = flowOf()
override val books: Flow<PagingData<BookThumbnailUio>> override val books: Flow<PagingData<BookThumbnailUio>>
get() = flowOf() get() = flowOf()

View file

@ -12,7 +12,8 @@ class BookThumbnailMock {
title = "Foundation", title = "Foundation",
author = "Asimov", author = "Asimov",
date = "1951", date = "1951",
series = "Foundation - 1" series = "Foundation - 1",
isNew = false,
) )
} }
@ -25,6 +26,7 @@ class BookThumbnailMock {
author = "Asimov", author = "Asimov",
date = "1988", date = "1988",
series = "Foundation - 1", series = "Foundation - 1",
isNew = false,
), ),
BookThumbnailUio( BookThumbnailUio(
id = 78, id = 78,
@ -33,6 +35,7 @@ class BookThumbnailMock {
author = "Asimov", author = "Asimov",
date = "1993", date = "1993",
series = "Foundation - 2", series = "Foundation - 2",
isNew = false,
), ),
BookThumbnailUio( BookThumbnailUio(
id = 90, id = 90,
@ -41,6 +44,7 @@ class BookThumbnailMock {
author = "Asimov", author = "Asimov",
date = "1951", date = "1951",
series = "Foundation - 3", series = "Foundation - 3",
isNew = false,
), ),
BookThumbnailUio( BookThumbnailUio(
id = 184, id = 184,
@ -49,6 +53,7 @@ class BookThumbnailMock {
author = "Asimov", author = "Asimov",
date = "1952", date = "1952",
series = "Foundation - 4", series = "Foundation - 4",
isNew = false,
), ),
BookThumbnailUio( BookThumbnailUio(
id = 185, id = 185,
@ -57,6 +62,7 @@ class BookThumbnailMock {
author = "Asimov", author = "Asimov",
date = "1953", date = "1953",
series = "Foundation - 5", series = "Foundation - 5",
isNew = false,
), ),
BookThumbnailUio( BookThumbnailUio(
id = 119, id = 119,
@ -65,6 +71,7 @@ class BookThumbnailMock {
author = "Asimov", author = "Asimov",
date = "1982", date = "1982",
series = "Foundation - 6", series = "Foundation - 6",
isNew = false,
), ),
BookThumbnailUio( BookThumbnailUio(
id = 163, id = 163,
@ -73,233 +80,7 @@ class BookThumbnailMock {
author = "Asimov", author = "Asimov",
date = "1986", date = "1986",
series = "Foundation - 7", series = "Foundation - 7",
), isNew = false,
BookThumbnailUio(
id = 112,
title = "Prélude à Fondation",
genre = "Sci-Fi",
author = "Asimov",
date = "1988",
series = "Foundation - 1",
),
BookThumbnailUio(
id = 78,
title = "L'Aube de Fondation",
genre = "Sci-Fi",
author = "Asimov",
date = "1993",
series = "Foundation - 2",
),
BookThumbnailUio(
id = 90,
title = "Fondation",
genre = "Sci-Fi",
author = "Asimov",
date = "1951",
series = "Foundation - 3",
),
BookThumbnailUio(
id = 184,
title = "Fondation et Empire",
genre = "Sci-Fi",
author = "Asimov",
date = "1952",
series = "Foundation - 4",
),
BookThumbnailUio(
id = 185,
title = "Seconde Fondation",
genre = "Sci-Fi",
author = "Asimov",
date = "1953",
series = "Foundation - 5",
),
BookThumbnailUio(
id = 119,
title = "Fondation foudroyée",
genre = "Sci-Fi",
author = "Asimov",
date = "1982",
series = "Foundation - 6",
),
BookThumbnailUio(
id = 163,
title = "Terre et Fondation",
genre = "Sci-Fi",
author = "Asimov",
date = "1986",
series = "Foundation - 7",
),
BookThumbnailUio(
id = 112,
title = "Prélude à Fondation",
genre = "Sci-Fi",
author = "Asimov",
date = "1988",
series = "Foundation - 1",
),
BookThumbnailUio(
id = 78,
title = "L'Aube de Fondation",
genre = "Sci-Fi",
author = "Asimov",
date = "1993",
series = "Foundation - 2",
),
BookThumbnailUio(
id = 90,
title = "Fondation",
genre = "Sci-Fi",
author = "Asimov",
date = "1951",
series = "Foundation - 3",
),
BookThumbnailUio(
id = 184,
title = "Fondation et Empire",
genre = "Sci-Fi",
author = "Asimov",
date = "1952",
series = "Foundation - 4",
),
BookThumbnailUio(
id = 185,
title = "Seconde Fondation",
genre = "Sci-Fi",
author = "Asimov",
date = "1953",
series = "Foundation - 5",
),
BookThumbnailUio(
id = 119,
title = "Fondation foudroyée",
genre = "Sci-Fi",
author = "Asimov",
date = "1982",
series = "Foundation - 6",
),
BookThumbnailUio(
id = 163,
title = "Terre et Fondation",
genre = "Sci-Fi",
author = "Asimov",
date = "1986",
series = "Foundation - 7",
),
BookThumbnailUio(
id = 112,
title = "Prélude à Fondation",
genre = "Sci-Fi",
author = "Asimov",
date = "1988",
series = "Foundation - 1",
),
BookThumbnailUio(
id = 78,
title = "L'Aube de Fondation",
genre = "Sci-Fi",
author = "Asimov",
date = "1993",
series = "Foundation - 2",
),
BookThumbnailUio(
id = 90,
title = "Fondation",
genre = "Sci-Fi",
author = "Asimov",
date = "1951",
series = "Foundation - 3",
),
BookThumbnailUio(
id = 184,
title = "Fondation et Empire",
genre = "Sci-Fi",
author = "Asimov",
date = "1952",
series = "Foundation - 4",
),
BookThumbnailUio(
id = 185,
title = "Seconde Fondation",
genre = "Sci-Fi",
author = "Asimov",
date = "1953",
series = "Foundation - 5",
),
BookThumbnailUio(
id = 119,
title = "Fondation foudroyée",
genre = "Sci-Fi",
author = "Asimov",
date = "1982",
series = "Foundation - 6",
),
BookThumbnailUio(
id = 163,
title = "Terre et Fondation",
genre = "Sci-Fi",
author = "Asimov",
date = "1986",
series = "Foundation - 7",
),
BookThumbnailUio(
id = 112,
title = "Prélude à Fondation",
genre = "Sci-Fi",
author = "Asimov",
date = "1988",
series = "Foundation - 1",
),
BookThumbnailUio(
id = 78,
title = "L'Aube de Fondation",
genre = "Sci-Fi",
author = "Asimov",
date = "1993",
series = "Foundation - 2",
),
BookThumbnailUio(
id = 90,
title = "Fondation",
genre = "Sci-Fi",
author = "Asimov",
date = "1951",
series = "Foundation - 3",
),
BookThumbnailUio(
id = 184,
title = "Fondation et Empire",
genre = "Sci-Fi",
author = "Asimov",
date = "1952",
series = "Foundation - 4",
),
BookThumbnailUio(
id = 185,
title = "Seconde Fondation",
genre = "Sci-Fi",
author = "Asimov",
date = "1953",
series = "Foundation - 5",
),
BookThumbnailUio(
id = 119,
title = "Fondation foudroyée",
genre = "Sci-Fi",
author = "Asimov",
date = "1982",
series = "Foundation - 6",
),
BookThumbnailUio(
id = 163,
title = "Terre et Fondation",
genre = "Sci-Fi",
author = "Asimov",
date = "1986",
series = "Foundation - 7",
), ),
) )
} }