Fix some layout.
This commit is contained in:
		
							parent
							
								
									9a5cd11782
								
							
						
					
					
						commit
						f79445c12c
					
				
					 10 changed files with 121 additions and 60 deletions
				
			
		| 
						 | 
				
			
			@ -16,10 +16,10 @@ class BookRepository : IBookRepository {
 | 
			
		|||
    override fun getAll(): List<Book> =
 | 
			
		||||
        database.bookDao().getAll().map { it.toBook() }
 | 
			
		||||
 | 
			
		||||
    override fun getNews(): DataSource.Factory<Int, Book> =
 | 
			
		||||
    override fun getNewsSource(): DataSource.Factory<Int, Book> =
 | 
			
		||||
        database.bookDao().getNews().map { it.toBook() }
 | 
			
		||||
 | 
			
		||||
    override fun getBook(): DataSource.Factory<Int, Book> =
 | 
			
		||||
    override fun getBooksSource(): DataSource.Factory<Int, Book> =
 | 
			
		||||
        database.bookDao().getBook().map { it.toBook() }
 | 
			
		||||
 | 
			
		||||
    override suspend fun update(data: List<Book>) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,9 +7,9 @@ interface IBookRepository {
 | 
			
		|||
 | 
			
		||||
    fun getAll(): List<Book>
 | 
			
		||||
 | 
			
		||||
    fun getNews(): DataSource.Factory<Int, Book>
 | 
			
		||||
    fun getNewsSource(): DataSource.Factory<Int, Book>
 | 
			
		||||
 | 
			
		||||
    fun getBook(): DataSource.Factory<Int, Book>
 | 
			
		||||
    fun getBooksSource(): DataSource.Factory<Int, Book>
 | 
			
		||||
 | 
			
		||||
    suspend fun update(data: List<Book>)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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,
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -31,8 +31,8 @@ fun HomePage(
 | 
			
		|||
 | 
			
		||||
    // https://issuetracker.google.com/issues/177245496
 | 
			
		||||
    val data: LazyPagingItems<BookThumbnailUio> = 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))
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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")
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,
 | 
			
		||||
) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,5 +8,5 @@ val Purple700 = Color(0xFF3700B3)
 | 
			
		|||
val Teal200 = Color(0xFF03DAC5)
 | 
			
		||||
 | 
			
		||||
val Green600 = Color(0xFF43a047)
 | 
			
		||||
val Green600L = Color(0XFF76d275)
 | 
			
		||||
val Green600D = Color(0XFF00701a)
 | 
			
		||||
val Green600L = Color(0xFF76d275)
 | 
			
		||||
val Green600D = Color(0xFF00701a)
 | 
			
		||||
| 
						 | 
				
			
			@ -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>(IBooksViewModel.State.Initial)
 | 
			
		||||
    override val state: LiveData<IBooksViewModel.State> get() = _state
 | 
			
		||||
 | 
			
		||||
    private val bookSource
 | 
			
		||||
        get() = bookRepository.getBook()
 | 
			
		||||
    private val bookSource: () -> PagingSource<Int, BookThumbnailUio>
 | 
			
		||||
        get() = bookRepository.getBooksSource()
 | 
			
		||||
            .map { it.toThumbnail() }
 | 
			
		||||
            .asPagingSourceFactory(Dispatchers.Default)
 | 
			
		||||
            .asPagingSourceFactory(Dispatchers.IO)
 | 
			
		||||
 | 
			
		||||
    override val books: Flow<PagingData<BookThumbnailUio>> = Pager(
 | 
			
		||||
        config = PagingConfig(pageSize = PAGING_SIZE),
 | 
			
		||||
        pagingSourceFactory = bookSource
 | 
			
		||||
    ).flow
 | 
			
		||||
 | 
			
		||||
    private val newsSource
 | 
			
		||||
        get() = bookRepository.getNews()
 | 
			
		||||
    private val newsSource: () -> PagingSource<Int, BookThumbnailUio>
 | 
			
		||||
        get() = bookRepository.getNewsSource()
 | 
			
		||||
            .map { it.toThumbnail() }
 | 
			
		||||
            .asPagingSourceFactory(Dispatchers.Default)
 | 
			
		||||
            .asPagingSourceFactory(Dispatchers.IO)
 | 
			
		||||
 | 
			
		||||
    override val news: Flow<PagingData<BookThumbnailUio>> = 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 ?: "",
 | 
			
		||||
    )
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue