diff --git a/app/src/main/java/com/pixelized/biblib/repository/book/BookRepository.kt b/app/src/main/java/com/pixelized/biblib/repository/book/BookRepository.kt index a66f684..54935e8 100644 --- a/app/src/main/java/com/pixelized/biblib/repository/book/BookRepository.kt +++ b/app/src/main/java/com/pixelized/biblib/repository/book/BookRepository.kt @@ -16,10 +16,10 @@ class BookRepository : IBookRepository { override fun getAll(): List = database.bookDao().getAll().map { it.toBook() } - override fun getNews(): DataSource.Factory = + override fun getNewsSource(): DataSource.Factory = database.bookDao().getNews().map { it.toBook() } - override fun getBook(): DataSource.Factory = + override fun getBooksSource(): DataSource.Factory = database.bookDao().getBook().map { it.toBook() } override suspend fun update(data: List) { diff --git a/app/src/main/java/com/pixelized/biblib/repository/book/IBookRepository.kt b/app/src/main/java/com/pixelized/biblib/repository/book/IBookRepository.kt index 88a32ca..e1e0e62 100644 --- a/app/src/main/java/com/pixelized/biblib/repository/book/IBookRepository.kt +++ b/app/src/main/java/com/pixelized/biblib/repository/book/IBookRepository.kt @@ -7,9 +7,9 @@ interface IBookRepository { fun getAll(): List - fun getNews(): DataSource.Factory + fun getNewsSource(): DataSource.Factory - fun getBook(): DataSource.Factory + fun getBooksSource(): DataSource.Factory suspend fun update(data: List) } \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/biblib/ui/composable/items/BookItem.kt b/app/src/main/java/com/pixelized/biblib/ui/composable/items/BookItem.kt index 9088059..ba22021 100644 --- a/app/src/main/java/com/pixelized/biblib/ui/composable/items/BookItem.kt +++ b/app/src/main/java/com/pixelized/biblib/ui/composable/items/BookItem.kt @@ -3,10 +3,7 @@ package com.pixelized.biblib.ui.composable.items import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.Card -import androidx.compose.material.Icon -import androidx.compose.material.MaterialTheme -import androidx.compose.material.Text +import androidx.compose.material.* import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.NavigateNext import androidx.compose.runtime.Composable @@ -34,6 +31,18 @@ private val THUMBNAIL_HEIGHT: Dp = 96.dp @Composable fun BookItem( + thumbnail: BookThumbnailUio?, + onClick: ((BookThumbnailUio) -> Unit)? = null, +) { + if (thumbnail != null) { + FilledBookItem(thumbnail, onClick) + } else { + EmptyBookItem() + } +} + +@Composable +private fun FilledBookItem( thumbnail: BookThumbnailUio, onClick: ((BookThumbnailUio) -> Unit)? = null, ) { @@ -78,24 +87,12 @@ fun BookItem( overflow = TextOverflow.Ellipsis, softWrap = false, ) - Row( - modifier = Modifier.weight(1f), - verticalAlignment = Alignment.Bottom - ) { + thumbnail.date?.let { date -> + Spacer(modifier = Modifier.weight(1f)) Text( + modifier = Modifier.align(Alignment.End), style = typography.caption, - text = thumbnail.genre, - overflow = TextOverflow.Ellipsis, - softWrap = false, - ) - Spacer( - modifier = Modifier - .widthIn(min = 4.dp) - .weight(1f) - ) - Text( - style = typography.caption, - text = thumbnail.date, + text = date, overflow = TextOverflow.Ellipsis, softWrap = false, ) @@ -109,13 +106,61 @@ fun BookItem( } } +@Composable +fun EmptyBookItem() { + Card( + modifier = Modifier + .fillMaxWidth() + .wrapContentHeight(), + elevation = 4.dp, + ) { + Row( + modifier = Modifier.height(THUMBNAIL_HEIGHT), + ) { + + Placeholder( + modifier = Modifier + .size(THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT) + .clip(RoundedCornerShape(4.dp)), + ) + Column( + modifier = Modifier + .padding(8.dp) + .weight(1f) + ) { + Placeholder( + modifier = Modifier.size(200.dp, 24.dp) + ) + Placeholder( + modifier = Modifier + .size(80.dp, 16.dp) + .padding(top = 4.dp) + ) + Spacer(modifier = Modifier.weight(1f)) + Placeholder( + modifier = Modifier + .size(60.dp, 14.dp) + .align(Alignment.End) + ) + } + Icon( + modifier = Modifier.align(Alignment.CenterVertically), + imageVector = Icons.Default.NavigateNext, contentDescription = "" + ) + } + } +} + +@Composable +private fun Placeholder(modifier: Modifier) = Surface(modifier = modifier, elevation = 4.dp) {} + @Preview @Composable fun BookItemLightPreview() { Bob[BitmapCache::class] = BitmapCache(LocalContext.current) BibLibTheme { val mock = BookThumbnailMock() - BookItem(thumbnail = mock.bookThumbnail) + FilledBookItem(thumbnail = mock.bookThumbnail) } } @@ -125,6 +170,22 @@ fun BookItemDarkPreview() { Bob[BitmapCache::class] = BitmapCache(LocalContext.current) BibLibTheme(darkTheme = true) { val mock = BookThumbnailMock() - BookItem(thumbnail = mock.bookThumbnail) + FilledBookItem(thumbnail = mock.bookThumbnail) + } +} + +@Preview +@Composable +fun EmptyBookItemLightPreview() { + BibLibTheme { + EmptyBookItem() + } +} + +@Preview +@Composable +fun EmptyBookItemDarkPreview() { + BibLibTheme(darkTheme = true) { + EmptyBookItem() } } \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/biblib/ui/composable/pages/DetailPage.kt b/app/src/main/java/com/pixelized/biblib/ui/composable/pages/DetailPage.kt index 683ed11..9ece3fd 100644 --- a/app/src/main/java/com/pixelized/biblib/ui/composable/pages/DetailPage.kt +++ b/app/src/main/java/com/pixelized/biblib/ui/composable/pages/DetailPage.kt @@ -22,6 +22,7 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel @@ -121,16 +122,14 @@ fun DetailPage(book: BookUio) { title = stringResource(id = R.string.detail_language), label = book.language, ) - TitleLabel( - title = stringResource(id = R.string.detail_release), - label = book.date, - ) + book.date?.let { + TitleLabel( + title = stringResource(id = R.string.detail_release), + label = it, + ) + } } Row(modifier = Modifier.padding(bottom = 16.dp)) { - TitleLabel( - title = stringResource(id = R.string.detail_genre), - label = book.genre, - ) TitleLabel( title = stringResource(id = R.string.detail_series), label = book.series ?: "-", @@ -161,6 +160,7 @@ private fun RowScope.TitleLabel( ) Text( style = typography.body1, + textAlign = TextAlign.Center, text = label, ) } diff --git a/app/src/main/java/com/pixelized/biblib/ui/composable/pages/HomePage.kt b/app/src/main/java/com/pixelized/biblib/ui/composable/pages/HomePage.kt index 94ae6c3..d276f43 100644 --- a/app/src/main/java/com/pixelized/biblib/ui/composable/pages/HomePage.kt +++ b/app/src/main/java/com/pixelized/biblib/ui/composable/pages/HomePage.kt @@ -31,8 +31,8 @@ fun HomePage( // https://issuetracker.google.com/issues/177245496 val data: LazyPagingItems = when (currentPage) { - is Page.Home.New -> booksViewModel.books.collectAsLazyPagingItems() - else -> booksViewModel.news.collectAsLazyPagingItems() + is Page.Home.New -> booksViewModel.news.collectAsLazyPagingItems() + else -> booksViewModel.books.collectAsLazyPagingItems() } val lazyListState = rememberLazyListState() @@ -45,7 +45,7 @@ fun HomePage( state = lazyListState, ) { items(data) { thumbnail -> - BookItem(thumbnail = thumbnail!!) { item -> + BookItem(thumbnail) { item -> navigationViewModel.navigateTo(Page.Detail(item.id)) } } diff --git a/app/src/main/java/com/pixelized/biblib/ui/data/BookThumbnailUio.kt b/app/src/main/java/com/pixelized/biblib/ui/data/BookThumbnailUio.kt index 5657c53..7afaa95 100644 --- a/app/src/main/java/com/pixelized/biblib/ui/data/BookThumbnailUio.kt +++ b/app/src/main/java/com/pixelized/biblib/ui/data/BookThumbnailUio.kt @@ -8,7 +8,7 @@ data class BookThumbnailUio( val genre: String, val title: String, val author: String, - val date: String, + val date: String?, val isNew: Boolean, ) { val cover: URL = URL("${THUMBNAIL_URL}/$id.jpg") diff --git a/app/src/main/java/com/pixelized/biblib/ui/data/BookUio.kt b/app/src/main/java/com/pixelized/biblib/ui/data/BookUio.kt index 4446036..86509ab 100644 --- a/app/src/main/java/com/pixelized/biblib/ui/data/BookUio.kt +++ b/app/src/main/java/com/pixelized/biblib/ui/data/BookUio.kt @@ -7,10 +7,9 @@ data class BookUio( val id: Int, val title: String, val author: String, - val genre: String, val rating: Float, val language: String, - val date: String, + val date: String?, val series: String?, val description: String, ) { diff --git a/app/src/main/java/com/pixelized/biblib/ui/theme/Color.kt b/app/src/main/java/com/pixelized/biblib/ui/theme/Color.kt index e443acf..808a6d1 100644 --- a/app/src/main/java/com/pixelized/biblib/ui/theme/Color.kt +++ b/app/src/main/java/com/pixelized/biblib/ui/theme/Color.kt @@ -8,5 +8,5 @@ val Purple700 = Color(0xFF3700B3) val Teal200 = Color(0xFF03DAC5) val Green600 = Color(0xFF43a047) -val Green600L = Color(0XFF76d275) -val Green600D = Color(0XFF00701a) \ No newline at end of file +val Green600L = Color(0xFF76d275) +val Green600D = Color(0xFF00701a) \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/biblib/ui/viewmodel/book/BooksViewModel.kt b/app/src/main/java/com/pixelized/biblib/ui/viewmodel/book/BooksViewModel.kt index 79d9856..a3b48b1 100644 --- a/app/src/main/java/com/pixelized/biblib/ui/viewmodel/book/BooksViewModel.kt +++ b/app/src/main/java/com/pixelized/biblib/ui/viewmodel/book/BooksViewModel.kt @@ -8,6 +8,7 @@ import androidx.lifecycle.viewModelScope import androidx.paging.Pager import androidx.paging.PagingConfig import androidx.paging.PagingData +import androidx.paging.PagingSource import com.pixelized.biblib.model.Book import com.pixelized.biblib.network.client.IBibLibClient import com.pixelized.biblib.network.factory.BookFactory @@ -27,25 +28,26 @@ class BooksViewModel : ViewModel(), IBooksViewModel { private val client: IBibLibClient by inject() private val apiCache: IAPICacheRepository by inject() - private val formatter = SimpleDateFormat("MMMM yyyy", Locale.getDefault()) + private val formatter_long = SimpleDateFormat("MMMM yyyy", Locale.getDefault()) + private val formatter_short = SimpleDateFormat("MMM yyyy", Locale.getDefault()) private val _state = MutableLiveData(IBooksViewModel.State.Initial) override val state: LiveData get() = _state - private val bookSource - get() = bookRepository.getBook() + private val bookSource: () -> PagingSource + get() = bookRepository.getBooksSource() .map { it.toThumbnail() } - .asPagingSourceFactory(Dispatchers.Default) + .asPagingSourceFactory(Dispatchers.IO) override val books: Flow> = Pager( config = PagingConfig(pageSize = PAGING_SIZE), pagingSourceFactory = bookSource ).flow - private val newsSource - get() = bookRepository.getNews() + private val newsSource: () -> PagingSource + get() = bookRepository.getNewsSource() .map { it.toThumbnail() } - .asPagingSourceFactory(Dispatchers.Default) + .asPagingSourceFactory(Dispatchers.IO) override val news: Flow> = Pager( config = PagingConfig(pageSize = PAGING_SIZE), @@ -107,7 +109,11 @@ class BooksViewModel : ViewModel(), IBooksViewModel { genre = genre?.joinToString { it.name } ?: "", title = title, author = author.joinToString { it.name }, - date = formatter.format(releaseDate).capitalize(Locale.getDefault()), + date = if (releaseDate.time < 0) { + null + } else { + formatter_long.format(releaseDate).capitalize(Locale.getDefault()) + }, isNew = isNew, ) @@ -115,10 +121,13 @@ class BooksViewModel : ViewModel(), IBooksViewModel { id = id, title = title, author = author.joinToString { it.name }, - genre = genre?.joinToString { it.name } ?: "", rating = rating?.toFloat() ?: 0.0f, language = language?.displayLanguage?.capitalize(Locale.getDefault()) ?: "", - date = formatter.format(releaseDate).capitalize(Locale.getDefault()), + date = if (releaseDate.time < 0) { + null + } else { + formatter_short.format(releaseDate).capitalize(Locale.getDefault()) + }, series = series?.name, description = synopsis ?: "", ) diff --git a/app/src/main/java/com/pixelized/biblib/utils/mock/BookMock.kt b/app/src/main/java/com/pixelized/biblib/utils/mock/BookMock.kt index dc33956..dad24e4 100644 --- a/app/src/main/java/com/pixelized/biblib/utils/mock/BookMock.kt +++ b/app/src/main/java/com/pixelized/biblib/utils/mock/BookMock.kt @@ -5,7 +5,6 @@ import com.pixelized.biblib.ui.data.BookUio class BookMock { val book: BookUio = BookUio( id = 90, - genre = "Sci-Fi", title = "Foundation", author = "Asimov", date = "1951", @@ -19,7 +18,6 @@ class BookMock { 112 to BookUio( id = 112, title = "Prélude à Fondation", - genre = "Sci-Fi", author = "Asimov", date = "1988", series = "Foundation - 1", @@ -30,7 +28,6 @@ class BookMock { 78 to BookUio( id = 78, title = "L'Aube de Fondation", - genre = "Sci-Fi", author = "Asimov", date = "1993", series = "Foundation - 2", @@ -41,7 +38,6 @@ class BookMock { 90 to BookUio( id = 90, title = "Fondation", - genre = "Sci-Fi", author = "Asimov", date = "1951", series = "Foundation - 3", @@ -52,7 +48,6 @@ class BookMock { 184 to BookUio( id = 184, title = "Fondation et Empire", - genre = "Sci-Fi", author = "Asimov", date = "1952", series = "Foundation - 4", @@ -63,7 +58,6 @@ class BookMock { 185 to BookUio( id = 185, title = "Seconde Fondation", - genre = "Sci-Fi", author = "Asimov", date = "1953", series = "Foundation - 5", @@ -74,7 +68,6 @@ class BookMock { 119 to BookUio( id = 119, title = "Fondation foudroyée", - genre = "Sci-Fi", author = "Asimov", date = "1982", series = "Foundation - 6", @@ -85,7 +78,6 @@ class BookMock { 163 to BookUio( id = 163, title = "Terre et Fondation", - genre = "Sci-Fi", author = "Asimov", date = "1986", series = "Foundation - 7",