Add new book management
This commit is contained in:
parent
bb9e1b36f7
commit
a822d7f008
12 changed files with 63 additions and 236 deletions
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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(
|
||||||
|
|
|
||||||
|
|
@ -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>)
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
}
|
}
|
||||||
|
|
@ -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(
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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",
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue